Blast quite a bit of LOCALE_IO into the sun

After forcing the locale-specific read/writes out of our IO, we can
remove the global LOCALE_IO calls in many places.

Still to do: exporters, pcm, specctra, settings, drawing sheets,
plotters
This commit is contained in:
Seth Hillbrand 2025-07-14 15:30:42 -07:00
parent 55da0e46af
commit 6cd076eed4
32 changed files with 77 additions and 279 deletions

View File

@ -37,7 +37,6 @@
#include <utility>
#include <wx/tokenzr.h>
#include <kiface_base.h>
#include <locale_io.h>
DESIGN_BLOCK_INFO* DESIGN_BLOCK_LIST::GetDesignBlockInfo( const wxString& aLibNickname,
const wxString& aDesignBlockName )

View File

@ -42,7 +42,6 @@ class DESIGN_BLOCK_LIST_IMPL;
class PROGRESS_REPORTER;
class wxTopLevelWindow;
class KIWAY;
class LOCALE_IO;
class wxTextFile;
@ -114,7 +113,7 @@ protected:
}
/// lazily load stuff not filled in by constructor. This may throw IO_ERRORS.
virtual void load( const LOCALE_IO* locale = nullptr ) {};
virtual void load() {};
protected:
DESIGN_BLOCK_LIST* m_owner; ///< provides access to DESIGN_BLOCK_LIB_TABLE

View File

@ -23,7 +23,6 @@
#include <design_block.h>
#include <design_block_lib_table.h>
#include <kiway.h>
#include <locale_io.h>
#include <progress_reporter.h>
#include <string_utils.h>
#include <thread_pool.h>
@ -35,14 +34,13 @@
#include <wx/wfstream.h>
void DESIGN_BLOCK_INFO_IMPL::load( const LOCALE_IO* locale )
void DESIGN_BLOCK_INFO_IMPL::load()
{
DESIGN_BLOCK_LIB_TABLE* dbtable = m_owner->GetTable();
wxASSERT( dbtable );
std::unique_ptr<const DESIGN_BLOCK> design_block( dbtable->GetEnumeratedDesignBlock( m_nickname, m_dbname,
locale ) );
std::unique_ptr<const DESIGN_BLOCK> design_block( dbtable->GetEnumeratedDesignBlock( m_nickname, m_dbname ) );
if( design_block )
{
@ -148,14 +146,7 @@ bool DESIGN_BLOCK_LIST_IMPL::ReadDesignBlockFiles( DESIGN_BLOCK_LIB_TABLE* aTabl
void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks()
{
LOCALE_IO toggle_locale;
// Parse the design_blocks in parallel. WARNING! This requires changing the locale, which is
// GLOBAL. It is only thread safe to construct the LOCALE_IO before the threads are created,
// destroy it after they finish, and block the main (GUI) thread while they work. Any deviation
// from this will cause nasal demons.
//
// TODO: blast LOCALE_IO into the sun
// Parse the design_blocks in parallel.
SYNC_QUEUE<std::unique_ptr<DESIGN_BLOCK_INFO>> queue_parsed;
@ -164,7 +155,7 @@ void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks()
std::vector<std::future<size_t>> returns( num_elements );
auto db_thread =
[ this, &queue_parsed, &toggle_locale ]() -> size_t
[ this, &queue_parsed ]() -> size_t
{
wxString nickname;
@ -176,7 +167,7 @@ void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks()
CatchErrors(
[&]()
{
m_lib_table->DesignBlockEnumerate( dbnames, nickname, false, &toggle_locale );
m_lib_table->DesignBlockEnumerate( dbnames, nickname, false );
} );
for( wxString dbname : dbnames )
@ -184,7 +175,7 @@ void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks()
CatchErrors(
[&]()
{
auto* dbinfo = new DESIGN_BLOCK_INFO_IMPL( this, nickname, dbname, &toggle_locale );
auto* dbinfo = new DESIGN_BLOCK_INFO_IMPL( this, nickname, dbname );
queue_parsed.move_push( std::unique_ptr<DESIGN_BLOCK_INFO>( dbinfo ) );
} );

View File

@ -30,13 +30,11 @@
#include <design_block_info.h>
#include <core/sync_queue.h>
class LOCALE_IO;
class KICOMMON_API DESIGN_BLOCK_INFO_IMPL : public DESIGN_BLOCK_INFO
{
public:
DESIGN_BLOCK_INFO_IMPL( DESIGN_BLOCK_LIST* aOwner, const wxString& aNickname,
const wxString& aDesignBlockName, const LOCALE_IO* aLocale )
const wxString& aDesignBlockName )
{
m_nickname = aNickname;
m_dbname = aDesignBlockName;
@ -44,7 +42,7 @@ public:
m_owner = aOwner;
m_loaded = false;
load( aLocale );
load();
}
// A constructor for cached items
@ -73,7 +71,7 @@ public:
}
protected:
virtual void load( const LOCALE_IO* aLocale = nullptr ) override;
virtual void load() override;
};

View File

@ -39,7 +39,6 @@
#include <wx/dir.h>
#include <wx/hash.h>
#include <locale_io.h>
#define OPT_SEP '|' ///< options separator character
@ -334,23 +333,13 @@ long long DESIGN_BLOCK_LIB_TABLE::GenerateTimestamp( const wxString* aNickname )
void DESIGN_BLOCK_LIB_TABLE::DesignBlockEnumerate( wxArrayString& aDesignBlockNames, const wxString& aNickname,
bool aBestEfforts, const LOCALE_IO* aLocale )
bool aBestEfforts )
{
const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );
if( !aLocale )
{
LOCALE_IO toggle_locale;
row->plugin->DesignBlockEnumerate( aDesignBlockNames, row->GetFullURI( true ), aBestEfforts,
row->GetProperties() );
}
else
{
row->plugin->DesignBlockEnumerate( aDesignBlockNames, row->GetFullURI( true ), aBestEfforts,
row->GetProperties() );
}
row->plugin->DesignBlockEnumerate( aDesignBlockNames, row->GetFullURI( true ), aBestEfforts,
row->GetProperties() );
}
@ -401,34 +390,19 @@ static void setLibNickname( DESIGN_BLOCK* aModule, const wxString& aNickname,
const DESIGN_BLOCK*
DESIGN_BLOCK_LIB_TABLE::GetEnumeratedDesignBlock( const wxString& aNickname,
const wxString& aDesignBlockName,
const LOCALE_IO* aLocale )
const wxString& aDesignBlockName )
{
const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );
if( !aLocale )
{
LOCALE_IO toggle_locale;
return row->plugin->GetEnumeratedDesignBlock( row->GetFullURI( true ), aDesignBlockName,
row->GetProperties() );
}
else
{
return row->plugin->GetEnumeratedDesignBlock( row->GetFullURI( true ), aDesignBlockName,
row->GetProperties() );
}
return row->plugin->GetEnumeratedDesignBlock( row->GetFullURI( true ), aDesignBlockName,
row->GetProperties() );
}
bool DESIGN_BLOCK_LIB_TABLE::DesignBlockExists( const wxString& aNickname,
const wxString& aDesignBlockName )
{
// NOT THREAD-SAFE! LOCALE_IO is global!
LOCALE_IO toggle_locale;
try
{
const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true );
@ -448,10 +422,6 @@ DESIGN_BLOCK* DESIGN_BLOCK_LIB_TABLE::DesignBlockLoad( const wxString& aNickname
const wxString& aDesignBlockName,
bool aKeepUUID )
{
// NOT THREAD-SAFE! LOCALE_IO is global!
LOCALE_IO toggle_locale;
const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );
@ -468,10 +438,6 @@ DESIGN_BLOCK_LIB_TABLE::SAVE_T
DESIGN_BLOCK_LIB_TABLE::DesignBlockSave( const wxString& aNickname,
const DESIGN_BLOCK* aDesignBlock, bool aOverwrite )
{
// NOT THREAD-SAFE! LOCALE_IO is global!
LOCALE_IO toggle_locale;
const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );

View File

@ -39,7 +39,6 @@
#include <utility>
#include <wx/tokenzr.h>
#include <kiface_base.h>
#include <locale_io.h>
FOOTPRINT_INFO* FOOTPRINT_LIST::GetFootprintInfo( const wxString& aLibNickname,
const wxString& aFootprintName )

View File

@ -40,7 +40,6 @@
#include <wx/dir.h>
#include <wx/hash.h>
#include <locale_io.h>
#define OPT_SEP '|' ///< options separator character
@ -313,23 +312,13 @@ long long FP_LIB_TABLE::GenerateTimestamp( const wxString* aNickname )
void FP_LIB_TABLE::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aNickname,
bool aBestEfforts, const LOCALE_IO* aLocale )
bool aBestEfforts )
{
const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );
if( !aLocale )
{
LOCALE_IO toggle_locale;
row->plugin->FootprintEnumerate( aFootprintNames, row->GetFullURI( true ), aBestEfforts,
row->GetProperties() );
}
else
{
row->plugin->FootprintEnumerate( aFootprintNames, row->GetFullURI( true ), aBestEfforts,
row->GetProperties() );
}
row->plugin->FootprintEnumerate( aFootprintNames, row->GetFullURI( true ), aBestEfforts,
row->GetProperties() );
}
@ -379,33 +368,18 @@ static void setLibNickname( FOOTPRINT* aModule, const wxString& aNickname,
const FOOTPRINT* FP_LIB_TABLE::GetEnumeratedFootprint( const wxString& aNickname,
const wxString& aFootprintName,
const LOCALE_IO* aLocale )
const wxString& aFootprintName )
{
const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );
if( !aLocale )
{
LOCALE_IO toggle_locale;
return row->plugin->GetEnumeratedFootprint( row->GetFullURI( true ), aFootprintName,
row->GetProperties() );
}
else
{
return row->plugin->GetEnumeratedFootprint( row->GetFullURI( true ), aFootprintName,
row->GetProperties() );
}
return row->plugin->GetEnumeratedFootprint( row->GetFullURI( true ), aFootprintName,
row->GetProperties() );
}
bool FP_LIB_TABLE::FootprintExists( const wxString& aNickname, const wxString& aFootprintName )
{
// NOT THREAD-SAFE! LOCALE_IO is global!
LOCALE_IO toggle_locale;
try
{
const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true );
@ -424,10 +398,6 @@ bool FP_LIB_TABLE::FootprintExists( const wxString& aNickname, const wxString& a
FOOTPRINT* FP_LIB_TABLE::FootprintLoad( const wxString& aNickname,
const wxString& aFootprintName, bool aKeepUUID )
{
// NOT THREAD-SAFE! LOCALE_IO is global!
LOCALE_IO toggle_locale;
const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );
@ -443,10 +413,6 @@ FOOTPRINT* FP_LIB_TABLE::FootprintLoad( const wxString& aNickname,
FP_LIB_TABLE::SAVE_T FP_LIB_TABLE::FootprintSave( const wxString& aNickname,
const FOOTPRINT* aFootprint, bool aOverwrite )
{
// NOT THREAD-SAFE! LOCALE_IO is global!
LOCALE_IO toggle_locale;
const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true );
wxASSERT( row->plugin );

View File

@ -24,8 +24,6 @@
#include <sch_io/eagle/sch_io_eagle.h>
#include <locale_io.h>
#include <algorithm>
#include <memory>
#include <wx/filename.h>
@ -351,7 +349,6 @@ SCH_SHEET* SCH_IO_EAGLE::LoadSchematicFile( const wxString& aFileName, SCHEMATIC
const std::map<std::string, UTF8>* aProperties )
{
wxASSERT( !aFileName || aSchematic != nullptr );
LOCALE_IO toggle; // toggles on, then off, the C locale.
// Show the font substitution warnings
fontconfig::FONTCONFIG::SetReporter( &WXLOG_REPORTER::GetInstance() );
@ -559,8 +556,6 @@ void SCH_IO_EAGLE::ensureLoadedLibrary( const wxString& aLibraryPath )
return;
}
LOCALE_IO toggle; // toggles on, then off, the C locale.
if( m_progressReporter )
{
m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aLibraryPath ) );

View File

@ -37,7 +37,6 @@
#include <fmt/format.h>
#include <kiway.h>
#include <string_utils.h>
#include <locale_io.h>
#include <richio.h>
#include <trace_helpers.h>
#include <trigo.h>
@ -130,9 +129,7 @@ SCH_SHEET* SCH_IO_KICAD_LEGACY::LoadSchematicFile( const wxString& aFileName, SC
{
wxASSERT( !aFileName || aSchematic != nullptr );
LOCALE_IO toggle; // toggles on, then off, the C locale.
SCH_SHEET* sheet;
wxFileName fn = aFileName;
// Unfortunately child sheet file names the legacy schematic file format are not fully
@ -1502,8 +1499,6 @@ void SCH_IO_KICAD_LEGACY::SaveSchematicFile( const wxString& aFileName, SCH_SHEE
wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET object." );
wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
LOCALE_IO toggle; // toggles on, then off, the C locale, to write floating point values.
init( aSchematic, aProperties );
wxFileName fn = aFileName;
@ -1804,7 +1799,7 @@ void SCH_IO_KICAD_LEGACY::saveBitmap( const SCH_BITMAP& aBitmap )
m_out->Print( 0, "Pos %-4d %-4d\n",
schIUScale.IUToMils( aBitmap.GetPosition().x ),
schIUScale.IUToMils( aBitmap.GetPosition().y ) );
m_out->Print( "%s", fmt::format("Scale {:g}\n atof", refImage.GetImageScale()).c_str() );
m_out->Print( "%s", fmt::format("Scale {:g}\n", refImage.GetImageScale()).c_str() );
m_out->Print( 0, "Data\n" );
wxMemoryOutputStream stream;
@ -2123,8 +2118,6 @@ void SCH_IO_KICAD_LEGACY::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
const wxString& aLibraryPath,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
bool powerSymbolsOnly = ( aProperties &&
aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
@ -2144,8 +2137,6 @@ void SCH_IO_KICAD_LEGACY::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolL
const wxString& aLibraryPath,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
bool powerSymbolsOnly = ( aProperties &&
aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
@ -2165,8 +2156,6 @@ LIB_SYMBOL* SCH_IO_KICAD_LEGACY::LoadSymbol( const wxString& aLibraryPath,
const wxString& aSymbolName,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
cacheLib( aLibraryPath, aProperties );
LIB_SYMBOL_MAP::const_iterator it = m_cache->m_symbols.find( aSymbolName );
@ -2181,8 +2170,6 @@ LIB_SYMBOL* SCH_IO_KICAD_LEGACY::LoadSymbol( const wxString& aLibraryPath,
void SCH_IO_KICAD_LEGACY::SaveSymbol( const wxString& aLibraryPath, const LIB_SYMBOL* aSymbol,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
cacheLib( aLibraryPath, aProperties );
m_cache->AddSymbol( aSymbol );
@ -2195,8 +2182,6 @@ void SCH_IO_KICAD_LEGACY::SaveSymbol( const wxString& aLibraryPath, const LIB_SY
void SCH_IO_KICAD_LEGACY::DeleteSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
cacheLib( aLibraryPath, aProperties );
m_cache->DeleteSymbol( aSymbolName );
@ -2215,8 +2200,6 @@ void SCH_IO_KICAD_LEGACY::CreateLibrary( const wxString& aLibraryPath,
aLibraryPath.GetData() ) );
}
LOCALE_IO toggle;
delete m_cache;
m_cache = new SCH_IO_KICAD_LEGACY_LIB_CACHE( aLibraryPath );
m_cache->SetModified();

View File

@ -33,7 +33,6 @@
#include <sch_selection.h>
#include <font/fontconfig.h>
#include <io/kicad/kicad_io_utils.h>
#include <locale_io.h>
#include <progress_reporter.h>
#include <schematic.h>
#include <schematic_lexer.h>
@ -101,7 +100,6 @@ SCH_SHEET* SCH_IO_KICAD_SEXPR::LoadSchematicFile( const wxString& aFileName, SCH
{
wxASSERT( !aFileName || aSchematic != nullptr );
LOCALE_IO toggle; // toggles on, then off, the C locale.
SCH_SHEET* sheet;
wxFileName fn = aFileName;
@ -324,7 +322,6 @@ void SCH_IO_KICAD_SEXPR::LoadContent( LINE_READER& aReader, SCH_SHEET* aSheet, i
{
wxCHECK( aSheet, /* void */ );
LOCALE_IO toggle;
SCH_IO_KICAD_SEXPR_PARSER parser( &aReader );
parser.ParseSchematic( aSheet, true, aFileVersion );
@ -338,8 +335,6 @@ void SCH_IO_KICAD_SEXPR::SaveSchematicFile( const wxString& aFileName, SCH_SHEET
wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET object." );
wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
LOCALE_IO toggle; // toggles on, then off, the C locale, to write floating point values.
wxString sanityResult = aSheet->GetScreen()->GroupsSanityCheck();
if( sanityResult != wxEmptyString && m_queryUserCallback )
@ -520,7 +515,6 @@ void SCH_IO_KICAD_SEXPR::Format( SCH_SELECTION* aSelection, SCH_SHEET_PATH* aSel
{
wxCHECK( aSelection && aSelectionPath && aFormatter, /* void */ );
LOCALE_IO toggle;
SCH_SHEET_LIST sheets = aSchematic.Hierarchy();
m_schematic = &aSchematic;
@ -1583,8 +1577,6 @@ void SCH_IO_KICAD_SEXPR::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
const wxString& aLibraryPath,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
bool powerSymbolsOnly = ( aProperties &&
aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
@ -1604,8 +1596,6 @@ void SCH_IO_KICAD_SEXPR::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolLi
const wxString& aLibraryPath,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
bool powerSymbolsOnly = ( aProperties &&
aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
@ -1625,8 +1615,6 @@ LIB_SYMBOL* SCH_IO_KICAD_SEXPR::LoadSymbol( const wxString& aLibraryPath,
const wxString& aSymbolName,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
cacheLib( aLibraryPath, aProperties );
LIB_SYMBOL_MAP::const_iterator it = m_cache->m_symbols.find( aSymbolName );
@ -1652,8 +1640,6 @@ LIB_SYMBOL* SCH_IO_KICAD_SEXPR::LoadSymbol( const wxString& aLibraryPath,
void SCH_IO_KICAD_SEXPR::SaveSymbol( const wxString& aLibraryPath, const LIB_SYMBOL* aSymbol,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
cacheLib( aLibraryPath, aProperties );
m_cache->AddSymbol( aSymbol );
@ -1666,8 +1652,6 @@ void SCH_IO_KICAD_SEXPR::SaveSymbol( const wxString& aLibraryPath, const LIB_SYM
void SCH_IO_KICAD_SEXPR::DeleteSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
cacheLib( aLibraryPath, aProperties );
m_cache->DeleteSymbol( aSymbolName );
@ -1686,8 +1670,6 @@ void SCH_IO_KICAD_SEXPR::CreateLibrary( const wxString& aLibraryPath,
aLibraryPath.GetData() ) );
}
LOCALE_IO toggle;
delete m_cache;
m_cache = new SCH_IO_KICAD_SEXPR_LIB_CACHE( aLibraryPath );
m_cache->SetModified();
@ -1802,7 +1784,6 @@ std::vector<LIB_SYMBOL*> SCH_IO_KICAD_SEXPR::ParseLibSymbols( std::string& aSymb
std::string aSource,
int aFileVersion )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
LIB_SYMBOL* newSymbol = nullptr;
LIB_SYMBOL_MAP map;
@ -1829,7 +1810,6 @@ std::vector<LIB_SYMBOL*> SCH_IO_KICAD_SEXPR::ParseLibSymbols( std::string& aSymb
void SCH_IO_KICAD_SEXPR::FormatLibSymbol( LIB_SYMBOL* symbol, OUTPUTFORMATTER & formatter )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol( symbol, formatter );
}

View File

@ -28,7 +28,6 @@
#include <sch_shape.h>
#include <lib_symbol.h>
#include <sch_textbox.h>
#include <locale_io.h>
#include <macros.h>
#include <richio.h>
#include "sch_io_kicad_sexpr_lib_cache.h"
@ -63,10 +62,6 @@ void SCH_IO_KICAD_SEXPR_LIB_CACHE::Load()
wxString::Format( "Cannot use relative file paths in sexpr plugin to "
"open library '%s'.", m_libFileName.GetFullPath() ) );
// The current locale must use period as the decimal point.
// Yes, we did this earlier, but it's sadly not thread-safe.
LOCALE_IO toggle;
wxLogTrace( traceSchLegacyPlugin, "Loading sexpr symbol library file '%s'",
m_libFileName.GetFullPath() );
@ -89,8 +84,6 @@ void SCH_IO_KICAD_SEXPR_LIB_CACHE::Save( const std::optional<bool>& aOpt )
if( !m_isModified )
return;
LOCALE_IO toggle; // toggles on, then off, the C locale.
// Write through symlinks, don't replace them.
wxFileName fn = GetRealFile();
@ -139,11 +132,6 @@ void SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol( LIB_SYMBOL* aSymbol, OUTPUTFORMAT
{
wxCHECK_RET( aSymbol, "Invalid LIB_SYMBOL pointer." );
// The current locale must use period as the decimal point.
wxCHECK2( wxLocale::GetInfo( wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER ) == ".",
LOCALE_IO toggle );
// If we've requested to embed the fonts in the symbol, do so.
// Otherwise, clear the embedded fonts from the symbol. Embedded
// fonts will be used if available

View File

@ -74,7 +74,6 @@
#include <macros.h>
#include <richio.h>
#include <string_utils.h>
#include <locale_io.h>
#include <X2_gerber_attributes.h>
#include <view/view.h>
#include <gerbview_settings.h>
@ -481,8 +480,6 @@ bool EXCELLON_IMAGE::LoadFile( const wxString & aFullFileName, EXCELLON_DEFAULTS
wxString msg;
m_FileName = aFullFileName;
LOCALE_IO toggleIo;
// FILE_LINE_READER will close the file.
FILE_LINE_READER excellonReader( m_Current_File, m_FileName );

View File

@ -28,7 +28,6 @@
#include <confirm.h>
#include <string_utils.h>
#include <locale_io.h>
#include <lset.h>
#include <macros.h>
#include <trigo.h>
@ -57,8 +56,6 @@ GBR_TO_PCB_EXPORTER::~GBR_TO_PCB_EXPORTER()
bool GBR_TO_PCB_EXPORTER::ExportPcb( const int* aLayerLookUpTable, int aCopperLayers )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
m_fp = wxFopen( m_pcb_file_name, wxT( "wt" ) );
if( m_fp == nullptr )

View File

@ -32,7 +32,6 @@
#include <wildcards_and_files_ext.h>
#include <gerbview.h>
#include <richio.h>
#include <locale_io.h>
#include <string_utils.h>
#include <gerber_file_image.h>
#include <gerber_file_image_list.h>
@ -111,8 +110,6 @@ bool GERBER_JOBFILE_READER::ReadGerberJobFile()
if( jobFile == nullptr )
return false;
LOCALE_IO toggleIo;
FILE_LINE_READER jobfileReader( jobFile, m_filename.GetFullPath() ); // Will close jobFile
wxString data;

View File

@ -24,7 +24,6 @@
#include "ki_exception.h"
#include <string_utils.h>
#include <locale_io.h>
#include <gerbview.h>
#include <gerbview_frame.h>
#include <gerber_file_image.h>
@ -245,8 +244,6 @@ bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
m_FileName = aFullFileName;
LOCALE_IO toggleIo;
wxString msg;
while( true )

View File

@ -114,7 +114,9 @@ VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& aText, bool aExcellonMode )
line.push_back( *( aText++ ) );
}
double val = strtod( line.data(), nullptr );
double val;
wxString text( line.data() );
text.ToCDouble( &val );
if( is_float )
{
@ -202,7 +204,10 @@ VECTOR2I GERBER_FILE_IMAGE::ReadIJCoord( char*& aText )
line.push_back( *( aText++ ) );
}
double val = strtod( line.data(), nullptr );
double val;
wxString text( line.data() );
text.Trim( true ).Trim( false );
text.ToCDouble( &val );
if( is_float )
{
@ -314,7 +319,21 @@ double ReadDouble( char*& text, bool aSkipSeparator = true )
}
else
{
ret = strtod( text, &text );
wxString line( text );
auto endpos = line.find_first_not_of( "0123456789.-+eE" );
line.Trim( false );
line.ToCDouble( &ret );
if( endpos != wxString::npos )
{
// Advance the text pointer to the end of the number
text += endpos;
}
else
{
// If no non-number characters found, advance to the end of the string
text += line.length();
}
}
if( *text == ',' || isspace( *text ) )

View File

@ -158,13 +158,11 @@ public:
* \a aNickname.
* @param aNickname is a locator for the "library", it is a "name" in LIB_TABLE_ROW.
* @param aBestEfforts if true, don't throw on errors.
* @param aLocale a previously set-up locale. Currently required for multi-threading, as LOCALE_IO
* uses global storage.
*
* @throw IO_ERROR if the library cannot be found, or design block cannot be loaded.
*/
void DesignBlockEnumerate( wxArrayString& aDesignBlockNames, const wxString& aNickname,
bool aBestEfforts, const LOCALE_IO* aLocale = nullptr );
bool aBestEfforts );
/**
* Generate a hashed timestamp representing the last-mod-times of the library indicated
@ -202,8 +200,7 @@ public:
*
* The return value is const to allow it to return a reference to a cached item.
*/
const DESIGN_BLOCK* GetEnumeratedDesignBlock( const wxString& aNickname, const wxString& aDesignBlockName,
const LOCALE_IO* aLocale = nullptr );
const DESIGN_BLOCK* GetEnumeratedDesignBlock( const wxString& aNickname, const wxString& aDesignBlockName );
/**
* The set of return values from DesignBlockSave() below.
*/

View File

@ -46,7 +46,6 @@ class FOOTPRINT_LIST_IMPL;
class PROGRESS_REPORTER;
class wxTopLevelWindow;
class KIWAY;
class LOCALE_IO;
class wxTextFile;
@ -135,7 +134,7 @@ protected:
}
/// lazily load stuff not filled in by constructor. This may throw IO_ERRORS.
virtual void load( const LOCALE_IO* aLocale = nullptr ) { };
virtual void load() { };
FOOTPRINT_LIST* m_owner; ///< provides access to FP_LIB_TABLE

View File

@ -32,7 +32,6 @@
class FOOTPRINT;
class FP_LIB_TABLE_GRID;
class PCB_IO;
class LOCALE_IO;
/**
@ -144,13 +143,11 @@ public:
* @param aFootprintNames is the list to fill with the footprint names found in \a aNickname
* @param aNickname is a locator for the "library", it is a "name" in LIB_TABLE_ROW.
* @param aBestEfforts if true, don't throw on errors.
* @param aLocale a previously set-up locale. Currently required for multi-threading, as LOCALE_IO
* uses global storage.
*
* @throw IO_ERROR if the library cannot be found, or footprint cannot be loaded.
*/
void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aNickname,
bool aBestEfforts, const LOCALE_IO* aLocale = nullptr );
bool aBestEfforts );
/**
* Generate a hashed timestamp representing the last-mod-times of the library indicated
@ -183,14 +180,10 @@ public:
* A version of #FootprintLoad() for use after #FootprintEnumerate() for more efficient
* cache management.
*
* @param aLocale a previously set-up locale. Currently required for multi-threading, as LOCALE_IO
* uses global storage.
*
* The return value is const to allow it to return a reference to a cached item.
*/
const FOOTPRINT* GetEnumeratedFootprint( const wxString& aNickname,
const wxString& aFootprintName,
const LOCALE_IO* aLocale = nullptr );
const wxString& aFootprintName );
/**
* The set of return values from FootprintSave() below.
*/

View File

@ -22,6 +22,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <wx/app.h>
#include <wx/msgdlg.h>
@ -30,7 +32,6 @@
#include <class_regulator_data.h>
#include <datafile_read_write.h>
#include <string_utils.h>
#include <locale_io.h>
#include <macros.h>
#include <pcb_calculator_datafile_lexer.h>
#include <pcb_calculator_frame.h>
@ -53,8 +54,6 @@ bool PANEL_REGULATOR::ReadDataFile()
if( file == nullptr )
return false;
// Switch the locale to standard C (needed to read/write floating point numbers)
LOCALE_IO toggle;
m_RegulatorList.Clear();
PCB_CALCULATOR_DATAFILE* datafile = new PCB_CALCULATOR_DATAFILE( &m_RegulatorList );
@ -92,9 +91,6 @@ bool PANEL_REGULATOR::ReadDataFile()
bool PANEL_REGULATOR::WriteDataFile()
{
// Switch the locale to standard C (needed to read/write floating point numbers)
LOCALE_IO toggle;
auto datafile = std::make_unique<PCB_CALCULATOR_DATAFILE>( &m_RegulatorList );
try
@ -155,19 +151,19 @@ void PCB_CALCULATOR_DATAFILE::Format( OUTPUTFORMATTER* aFormatter,
aFormatter->Print( aNestLevel, "(%s %s\n", getTokenName( T_regulator ),
aFormatter->Quotew( item->m_Name ).c_str() );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_vref_min ),
item->m_VrefMin );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_vref_typ ),
item->m_VrefTyp );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_vref_max ),
item->m_VrefMax );
aFormatter->Print( aNestLevel + 1, "%s", fmt::format( "({} {:g})\n", getTokenName( T_reg_vref_min ),
item->m_VrefMin ).c_str() );
aFormatter->Print( aNestLevel + 1, "%s", fmt::format( "({} {:g})\n", getTokenName( T_reg_vref_typ ),
item->m_VrefTyp ).c_str() );
aFormatter->Print( aNestLevel + 1, "%s", fmt::format( "({} {:g})\n", getTokenName( T_reg_vref_max ),
item->m_VrefMax ).c_str() );
if( item->m_Type == 1 )
{
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_iadj_typ ),
item->m_IadjTyp );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_iadj_max ),
item->m_IadjMax );
aFormatter->Print( aNestLevel + 1, "%s", fmt::format( "({} {:g})\n", getTokenName( T_reg_iadj_typ ),
item->m_IadjTyp ).c_str() );
aFormatter->Print( aNestLevel + 1, "%s", fmt::format( "({} {:g})\n", getTokenName( T_reg_iadj_max ),
item->m_IadjMax ).c_str() );
}
aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_reg_type ),
@ -233,7 +229,10 @@ void PCB_CALCULATOR_DATAFILE_PARSER::ParseRegulatorDescr( PCB_CALCULATOR_DATAFIL
if( token != T_NUMBER )
Expecting( T_NUMBER );
sscanf( CurText(), "%lf", &val );
wxString text = CurText();
text.Trim( true ).Trim( false );
text.ToCDouble( &val );
NeedRIGHT();
return val;
};

View File

@ -27,7 +27,6 @@
#include <footprint_info.h>
#include <fp_lib_table.h>
#include <kiway.h>
#include <locale_io.h>
#include <lib_id.h>
#include <progress_reporter.h>
#include <string_utils.h>
@ -41,13 +40,13 @@
#include <wx/wfstream.h>
void FOOTPRINT_INFO_IMPL::load( const LOCALE_IO* aLocale )
void FOOTPRINT_INFO_IMPL::load()
{
FP_LIB_TABLE* fptable = m_owner->GetTable();
wxASSERT( fptable );
const FOOTPRINT* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname, aLocale );
const FOOTPRINT* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname );
if( footprint == nullptr ) // Should happen only with malformed/broken libraries
{
@ -165,14 +164,7 @@ bool FOOTPRINT_LIST_IMPL::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxStri
void FOOTPRINT_LIST_IMPL::loadFootprints()
{
LOCALE_IO toggle_locale;
// Parse the footprints in parallel. WARNING! This requires changing the locale, which is
// GLOBAL. It is only thread safe to construct the LOCALE_IO before the threads are created,
// destroy it after they finish, and block the main (GUI) thread while they work. Any deviation
// from this will cause nasal demons.
//
// TODO: blast LOCALE_IO into the sun
// Parse the footprints in parallel.
SYNC_QUEUE<std::unique_ptr<FOOTPRINT_INFO>> queue_parsed;
thread_pool& tp = GetKiCadThreadPool();
@ -180,7 +172,7 @@ void FOOTPRINT_LIST_IMPL::loadFootprints()
std::vector<std::future<size_t>> returns( num_elements );
auto fp_thread =
[ this, &queue_parsed, &toggle_locale ]() -> size_t
[ this, &queue_parsed ]() -> size_t
{
wxString nickname;
@ -192,7 +184,7 @@ void FOOTPRINT_LIST_IMPL::loadFootprints()
CatchErrors(
[&]()
{
m_lib_table->FootprintEnumerate( fpnames, nickname, false, &toggle_locale );
m_lib_table->FootprintEnumerate( fpnames, nickname, false );
} );
for( wxString fpname : fpnames )
@ -200,7 +192,7 @@ void FOOTPRINT_LIST_IMPL::loadFootprints()
CatchErrors(
[&]()
{
auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname, &toggle_locale );
auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname );
queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
} );

View File

@ -34,8 +34,7 @@ class LOCALE_IO;
class FOOTPRINT_INFO_IMPL : public FOOTPRINT_INFO
{
public:
FOOTPRINT_INFO_IMPL( FOOTPRINT_LIST* aOwner, const wxString& aNickname, const wxString& aFootprintName,
const LOCALE_IO* aLocale )
FOOTPRINT_INFO_IMPL( FOOTPRINT_LIST* aOwner, const wxString& aNickname, const wxString& aFootprintName )
{
m_nickname = aNickname;
m_fpname = aFootprintName;
@ -45,7 +44,7 @@ public:
m_owner = aOwner;
m_loaded = false;
load( aLocale );
load();
}
// A constructor for cached items
@ -77,7 +76,7 @@ public:
}
protected:
virtual void load( const LOCALE_IO* aLocale ) override;
virtual void load() override;
};

View File

@ -1265,7 +1265,7 @@ FOOTPRINT* PCB_BASE_FRAME::CreateNewFootprint( wxString aFootprintName, const wx
// Try to infer the footprint attributes from an existing footprint in the library
try
{
tbl->FootprintEnumerate( fpnames, aLibName, true, nullptr );
tbl->FootprintEnumerate( fpnames, aLibName, true );
if( !fpnames.empty() )
footprintAttrs = tbl->FootprintLoad( aLibName, fpnames.Last() )->GetAttributes();

View File

@ -64,7 +64,6 @@ Load() TODO's
#include <font/fontconfig.h>
#include <geometry/geometry_utils.h>
#include <string_utils.h>
#include <locale_io.h>
#include <trigo.h>
#include <progress_reporter.h>
#include <project.h>
@ -324,7 +323,6 @@ VECTOR2I inline PCB_IO_EAGLE::kicad_fontsize( const ECOORD& d, int aTextThicknes
BOARD* PCB_IO_EAGLE::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
wxXmlNode* doc;
fontconfig::FONTCONFIG::SetReporter( &WXLOG_REPORTER::GetInstance() );
@ -3198,7 +3196,6 @@ void PCB_IO_EAGLE::cacheLib( const wxString& aLibPath )
if( aLibPath != m_lib_path || m_timestamp != timestamp )
{
wxXmlNode* doc;
LOCALE_IO toggle; // toggles on, then off, the C locale.
deleteTemplates();

View File

@ -35,7 +35,6 @@
#include <font/fontconfig.h>
#include <footprint.h>
#include <pad.h>
#include <locale_io.h>
#include <macros.h>
#include <pcb_text.h>
#include <pcb_shape.h>
@ -934,8 +933,6 @@ FOOTPRINT* PCB_IO_GEDA::FootprintLoad( const wxString& aLibraryPath,
void PCB_IO_GEDA::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
init( aProperties );
validateCache( aLibraryPath );
@ -1036,8 +1033,6 @@ long long PCB_IO_GEDA::GetLibraryTimestamp( const wxString& aLibraryPath ) const
bool PCB_IO_GEDA::IsLibraryWritable( const wxString& aLibraryPath )
{
LOCALE_IO toggle;
init( nullptr );
validateCache( aLibraryPath );

View File

@ -71,7 +71,6 @@
#include <boost/ptr_container/ptr_map.hpp>
#include <string_utils.h>
#include <locale_io.h>
#include <macros.h>
#include <filter_reader.h>
#include <zones.h>
@ -469,8 +468,6 @@ bool PCB_IO_KICAD_LEGACY::CanReadFootprint( const wxString& aFileName ) const
BOARD* PCB_IO_KICAD_LEGACY::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
init( aProperties );
std::unique_ptr<BOARD> boardDeleter;
@ -3318,8 +3315,6 @@ bool PCB_IO_KICAD_LEGACY::DeleteLibrary( const wxString& aLibraryPath,
bool PCB_IO_KICAD_LEGACY::IsLibraryWritable( const wxString& aLibraryPath )
{
LOCALE_IO toggle;
init( nullptr );
cacheLib( aLibraryPath );

View File

@ -39,7 +39,6 @@
#include <io/kicad/kicad_io_utils.h>
#include <kiface_base.h>
#include <layer_range.h>
#include <locale_io.h>
#include <macros.h>
#include <pad.h>
#include <pcb_dimension.h>
@ -309,8 +308,6 @@ bool PCB_IO_KICAD_SEXPR::CanReadBoard( const wxString& aFileName ) const
void PCB_IO_KICAD_SEXPR::SaveBoard( const wxString& aFileName, BOARD* aBoard,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
wxString sanityResult = aBoard->GroupsSanityCheck();
if( sanityResult != wxEmptyString && m_queryUserCallback )
@ -379,8 +376,6 @@ BOARD_ITEM* PCB_IO_KICAD_SEXPR::Parse( const wxString& aClipboardSourceInput )
void PCB_IO_KICAD_SEXPR::Format( const BOARD_ITEM* aItem ) const
{
LOCALE_IO toggle; // public API function, perform anything convenient for caller
switch( aItem->Type() )
{
case PCB_T:
@ -3107,8 +3102,6 @@ void PCB_IO_KICAD_SEXPR::FootprintDelete( const wxString& aLibraryPath,
const wxString& aFootprintName,
const std::map<std::string, UTF8>* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
init( aProperties );
validateCache( aLibraryPath );
@ -3139,8 +3132,6 @@ void PCB_IO_KICAD_SEXPR::CreateLibrary( const wxString& aLibraryPath,
aLibraryPath.GetData() ) );
}
LOCALE_IO toggle;
init( aProperties );
delete m_cache;
@ -3229,8 +3220,6 @@ bool PCB_IO_KICAD_SEXPR::DeleteLibrary( const wxString& aLibraryPath,
bool PCB_IO_KICAD_SEXPR::IsLibraryWritable( const wxString& aLibraryPath )
{
LOCALE_IO toggle;
init( nullptr );
validateCache( aLibraryPath );

View File

@ -61,7 +61,6 @@
#include <pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h>
#include <pcb_plot_params_parser.h>
#include <pcb_plot_params.h>
#include <locale_io.h>
#include <zones.h>
#include <pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.h>
#include <convert_basic_shapes_to_polygon.h> // for RECT_CHAMFER_POSITIONS definition
@ -809,8 +808,6 @@ FP_3DMODEL* PCB_IO_KICAD_SEXPR_PARSER::parse3DModel()
bool PCB_IO_KICAD_SEXPR_PARSER::IsValidBoardHeader()
{
LOCALE_IO toggle;
m_groupInfos.clear();
// See Parse() - FOOTPRINTS can be prefixed with an initial block of single line comments,
@ -831,7 +828,6 @@ BOARD_ITEM* PCB_IO_KICAD_SEXPR_PARSER::Parse()
{
T token;
BOARD_ITEM* item;
LOCALE_IO toggle;
m_groupInfos.clear();

View File

@ -27,7 +27,6 @@
#include <build_version.h>
#include <macros.h>
#include <wildcards_and_files_ext.h>
#include <locale_io.h>
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>

View File

@ -33,7 +33,6 @@
#include <io/io_utils.h>
#include <board.h>
#include <locale_io.h>
#include <cerrno>
#include <wx/string.h>
@ -77,8 +76,6 @@ BOARD* PCB_IO_PCAD::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
PCAD_PCB pcb( m_board );
LOCALE_IO toggle; // toggles on, then off, the C locale.
LoadInputFile( aFileName, &xmlDoc );
pcb.ParseBoard( nullptr, &xmlDoc, wxT( "PCB" ) );
pcb.AddToBoard();

View File

@ -28,7 +28,6 @@
#include <config.h>
#include <kiway_player.h>
#include <wildcards_and_files_ext.h>
#include <locale_io.h>
#include <pcb_io/pcb_io_mgr.h>
#include <pcb_io/eagle/pcb_io_eagle.h>
@ -196,7 +195,6 @@ bool PCB_IO_MGR::ConvertLibrary( std::map<std::string, UTF8>* aOldFileProps, con
if( oldFileType == PCB_IO_MGR::FILE_TYPE_NONE )
return false;
LOCALE_IO toggle_locale;
IO_RELEASER<PCB_IO> oldFilePI( PCB_IO_MGR::PluginFind( oldFileType ) );
IO_RELEASER<PCB_IO> kicadPI( PCB_IO_MGR::PluginFind( PCB_IO_MGR::KICAD_SEXP ) );
wxArrayString fpNames;

View File

@ -56,7 +56,6 @@
#include <specctra.h>
#include <project/project_local_settings.h>
#include <wildcards_and_files_ext.h>
#include <locale_io.h>
#include <wx/app.h>
#include <wx/crt.h>
#include <wx/image.h>
@ -127,10 +126,6 @@ SETTINGS_MANAGER* GetSettingsManager()
PROJECT* GetDefaultProject()
{
// For some reasons, LoadProject() needs a C locale, so ensure we have the right locale
// This is mainly when running QA Python tests
LOCALE_IO dummy;
PROJECT* project = GetSettingsManager()->GetProject( "" );
if( !project )
@ -160,11 +155,6 @@ BOARD* LoadBoard( const wxString& aFileName, PCB_IO_MGR::PCB_FILE_T aFormat, boo
// By default only the BMP handler is available.
wxInitAllImageHandlers();
// Ensure the "C" locale is temporary set, before reading any file
// It also avoid wxWidget alerts about locale issues, later, when using Python 3
LOCALE_IO dummy;
PROJECT* project = GetSettingsManager()->GetProject( projectPath );
if( !project )
@ -281,10 +271,6 @@ BOARD* NewBoard( wxString& aFileName )
wxString projectPath = proFn.GetFullPath();
// Ensure the "C" locale is temporary set, before reading any file
// It also avoids wxWidgets alerts about locale issues, later, when using Python 3
LOCALE_IO dummy;
GetSettingsManager()->LoadProject( projectPath, false );
PROJECT* project = GetSettingsManager()->GetProject( projectPath );
@ -319,10 +305,6 @@ bool SaveBoard( wxString& aFileName, BOARD* aBoard, PCB_IO_MGR::PCB_FILE_T aForm
aBoard->BuildConnectivity();
aBoard->SynchronizeNetsAndNetClasses( false );
// Ensure the "C" locale is temporary set, before saving any file
// It also avoid wxWidget alerts about locale issues, later, when using Python 3
LOCALE_IO dummy;
try
{
PCB_IO_MGR::Save( aFormat, aFileName, aBoard, nullptr );