From 68d49400872a6e0b027bbbcbb82e547e39fe8ace Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sun, 13 Jul 2025 14:56:22 +0100 Subject: [PATCH] Thread-safety (potentially KICAD-VMX...) ... KICAD-6PV, KICAD-82, KICAD-R3A, and others. --- common/design_block_info.cpp | 11 +++++ common/design_block_info.h | 6 +-- common/design_block_info_impl.cpp | 6 +-- common/design_block_lib_table.cpp | 49 ++++++++++++++++--- common/design_block_tree_model_adapter.cpp | 2 +- common/footprint_info.cpp | 11 +++++ common/fp_lib_table.cpp | 47 +++++++++++++++--- cvpcb/display_footprints_frame.cpp | 2 +- cvpcb/readwrite_dlgs.cpp | 2 +- eeschema/generate_alias_info.cpp | 39 +++++++-------- include/design_block_lib_table.h | 11 +++-- include/footprint_info.h | 6 +-- include/fp_lib_table.h | 10 +++- pcbnew/files.cpp | 3 +- pcbnew/footprint_info_impl.cpp | 4 +- pcbnew/footprint_libraries_utils.cpp | 4 +- pcbnew/footprint_preview_panel.cpp | 4 +- pcbnew/footprint_viewer_frame.cpp | 2 +- pcbnew/generate_footprint_info.cpp | 25 +++++----- pcbnew/load_select_footprint.cpp | 8 +-- .../pcb_io/easyeda/pcb_io_easyeda_plugin.cpp | 11 ++--- pcbnew/pcb_io/geda/pcb_io_geda.cpp | 8 +-- .../kicad_legacy/pcb_io_kicad_legacy.cpp | 11 ++--- .../pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp | 9 +--- pcbnew/pcb_io/pcb_io_mgr.cpp | 7 +-- .../scripting/pcbnew_scripting_helpers.cpp | 2 +- qa/pcbnew_utils/board_file_utils.cpp | 3 +- 27 files changed, 190 insertions(+), 113 deletions(-) diff --git a/common/design_block_info.cpp b/common/design_block_info.cpp index 10c3582047..e915e73a29 100644 --- a/common/design_block_info.cpp +++ b/common/design_block_info.cpp @@ -37,6 +37,7 @@ #include #include #include +#include DESIGN_BLOCK_INFO* DESIGN_BLOCK_LIST::GetDesignBlockInfo( const wxString& aLibNickname, const wxString& aDesignBlockName ) @@ -95,6 +96,16 @@ bool DESIGN_BLOCK_INFO::InLibrary( const wxString& aLibrary ) const } +void DESIGN_BLOCK_INFO::ensure_loaded() +{ + // Lazy-loading. MUST NOT be called from multi-threaded environment. + LOCALE_IO toggle_locale; + + if( !m_loaded ) + load(); +} + + bool operator<( const DESIGN_BLOCK_INFO& lhs, const DESIGN_BLOCK_INFO& rhs ) { int retv = StrNumCmp( lhs.m_nickname, rhs.m_nickname, false ); diff --git a/common/design_block_info.h b/common/design_block_info.h index 58fe492d36..e14bb0f757 100644 --- a/common/design_block_info.h +++ b/common/design_block_info.h @@ -106,11 +106,7 @@ public: friend bool operator<( const DESIGN_BLOCK_INFO& lhs, const DESIGN_BLOCK_INFO& rhs ); protected: - void ensure_loaded() - { - if( !m_loaded ) - load(); - } + void ensure_loaded(); /// lazily load stuff not filled in by constructor. This may throw IO_ERRORS. virtual void load(){}; diff --git a/common/design_block_info_impl.cpp b/common/design_block_info_impl.cpp index 8ec9473710..fd80f64886 100644 --- a/common/design_block_info_impl.cpp +++ b/common/design_block_info_impl.cpp @@ -41,8 +41,8 @@ void DESIGN_BLOCK_INFO_IMPL::load() wxASSERT( dbtable ); - std::unique_ptr design_block( dbtable->GetEnumeratedDesignBlock( m_nickname, - m_dbname ) ); + std::unique_ptr design_block( dbtable->GetEnumeratedDesignBlock( m_nickname, m_dbname, + true ) ); if( design_block ) { @@ -176,7 +176,7 @@ void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks() CatchErrors( [&]() { - m_lib_table->DesignBlockEnumerate( dbnames, nickname, false ); + m_lib_table->DesignBlockEnumerate( dbnames, nickname, false, true ); } ); for( wxString dbname : dbnames ) diff --git a/common/design_block_lib_table.cpp b/common/design_block_lib_table.cpp index 2f06a5d4da..f89c2c9780 100644 --- a/common/design_block_lib_table.cpp +++ b/common/design_block_lib_table.cpp @@ -39,6 +39,7 @@ #include #include +#include #define OPT_SEP '|' ///< options separator character @@ -332,13 +333,24 @@ long long DESIGN_BLOCK_LIB_TABLE::GenerateTimestamp( const wxString* aNickname ) } -void DESIGN_BLOCK_LIB_TABLE::DesignBlockEnumerate( wxArrayString& aDesignBlockNames, - const wxString& aNickname, bool aBestEfforts ) +void DESIGN_BLOCK_LIB_TABLE::DesignBlockEnumerate( wxArrayString& aDesignBlockNames, const wxString& aNickname, + bool aBestEfforts, bool aThreadSafe ) { const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true ); wxASSERT( row->plugin ); - row->plugin->DesignBlockEnumerate( aDesignBlockNames, row->GetFullURI( true ), aBestEfforts, - row->GetProperties() ); + + if( !aThreadSafe ) + { + 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() ); + } } @@ -389,19 +401,34 @@ static void setLibNickname( DESIGN_BLOCK* aModule, const wxString& aNickname, const DESIGN_BLOCK* DESIGN_BLOCK_LIB_TABLE::GetEnumeratedDesignBlock( const wxString& aNickname, - const wxString& aDesignBlockName ) + const wxString& aDesignBlockName, + bool aThreadSafe ) { const DESIGN_BLOCK_LIB_TABLE_ROW* row = FindRow( aNickname, true ); wxASSERT( row->plugin ); - return row->plugin->GetEnumeratedDesignBlock( row->GetFullURI( true ), aDesignBlockName, - row->GetProperties() ); + if( !aThreadSafe ) + { + 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() ); + } } 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 ); @@ -421,6 +448,10 @@ 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 ); @@ -437,6 +468,10 @@ 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 ); diff --git a/common/design_block_tree_model_adapter.cpp b/common/design_block_tree_model_adapter.cpp index 31c3a1f6e2..a7c7b23cfc 100644 --- a/common/design_block_tree_model_adapter.cpp +++ b/common/design_block_tree_model_adapter.cpp @@ -141,7 +141,7 @@ wxString DESIGN_BLOCK_TREE_MODEL_ADAPTER::GenerateInfo( LIB_ID const& aLibId, in try { - db = m_libs->GetEnumeratedDesignBlock( aLibId.GetLibNickname(), aLibId.GetLibItemName() ); + db = m_libs->GetEnumeratedDesignBlock( aLibId.GetLibNickname(), aLibId.GetLibItemName(), false ); } catch( const IO_ERROR& ioe ) { diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp index 25ef8465b1..d0abe43bdc 100644 --- a/common/footprint_info.cpp +++ b/common/footprint_info.cpp @@ -39,6 +39,7 @@ #include #include #include +#include FOOTPRINT_INFO* FOOTPRINT_LIST::GetFootprintInfo( const wxString& aLibNickname, const wxString& aFootprintName ) @@ -97,6 +98,16 @@ bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const } +void FOOTPRINT_INFO::ensure_loaded() +{ + // Lazy-loading. MUST NOT be called from multi-threaded environment. + LOCALE_IO toggle_locale; + + if( !m_loaded ) + load(); +} + + bool operator<( const FOOTPRINT_INFO& lhs, const FOOTPRINT_INFO& rhs ) { int retv = StrNumCmp( lhs.m_nickname, rhs.m_nickname, false ); diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 1120d18683..befe56c4c1 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -40,6 +40,7 @@ #include #include +#include #define OPT_SEP '|' ///< options separator character @@ -307,12 +308,23 @@ long long FP_LIB_TABLE::GenerateTimestamp( const wxString* aNickname ) void FP_LIB_TABLE::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aNickname, - bool aBestEfforts ) + bool aBestEfforts, bool aThreadSafe ) { const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true ); wxASSERT( row->plugin ); - row->plugin->FootprintEnumerate( aFootprintNames, row->GetFullURI( true ), aBestEfforts, - row->GetProperties() ); + + if( !aThreadSafe ) + { + 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() ); + } } @@ -362,18 +374,33 @@ static void setLibNickname( FOOTPRINT* aModule, const wxString& aNickname, const FOOTPRINT* FP_LIB_TABLE::GetEnumeratedFootprint( const wxString& aNickname, - const wxString& aFootprintName ) + const wxString& aFootprintName, + bool aThreadSafe ) { const FP_LIB_TABLE_ROW* row = FindRow( aNickname, true ); wxASSERT( row->plugin ); - return row->plugin->GetEnumeratedFootprint( row->GetFullURI( true ), aFootprintName, - row->GetProperties() ); + if( !aThreadSafe ) + { + 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() ); + } } 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 ); @@ -392,6 +419,10 @@ 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 ); @@ -407,6 +438,10 @@ 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 ); diff --git a/cvpcb/display_footprints_frame.cpp b/cvpcb/display_footprints_frame.cpp index 5ee0a44436..2c793448fc 100644 --- a/cvpcb/display_footprints_frame.cpp +++ b/cvpcb/display_footprints_frame.cpp @@ -304,7 +304,7 @@ FOOTPRINT* DISPLAY_FOOTPRINTS_FRAME::GetFootprint( const wxString& aFootprintNam try { - if( const FOOTPRINT* fp = fpTable->GetEnumeratedFootprint( libNickname, fpName ) ) + if( const FOOTPRINT* fp = fpTable->GetEnumeratedFootprint( libNickname, fpName, false ) ) footprint = static_cast( fp->Duplicate( IGNORE_PARENT_GROUP ) ); } catch( const IO_ERROR& ioe ) diff --git a/cvpcb/readwrite_dlgs.cpp b/cvpcb/readwrite_dlgs.cpp index 4a102eb5d0..4689481eab 100644 --- a/cvpcb/readwrite_dlgs.cpp +++ b/cvpcb/readwrite_dlgs.cpp @@ -58,7 +58,7 @@ static int guessNickname( FP_LIB_TABLE* aTbl, LIB_ID* aFootprintId ) { wxArrayString fpnames; - aTbl->FootprintEnumerate( fpnames, nicks[libNdx], true ); + aTbl->FootprintEnumerate( fpnames, nicks[libNdx], true, false ); for( unsigned nameNdx = 0; nameNdx < fpnames.size(); ++nameNdx ) { diff --git a/eeschema/generate_alias_info.cpp b/eeschema/generate_alias_info.cpp index 882e810d27..b258b6861b 100644 --- a/eeschema/generate_alias_info.cpp +++ b/eeschema/generate_alias_info.cpp @@ -48,19 +48,13 @@ static const wxString LinkFormat = wxS( "__TEXT__" ); class FOOTPRINT_INFO_GENERATOR { - wxString m_html; - SYMBOL_LIB_TABLE* m_sym_lib_table; - LIB_ID const m_lib_id; - LIB_SYMBOL* m_symbol; - int m_unit; - public: - FOOTPRINT_INFO_GENERATOR( SYMBOL_LIB_TABLE* aSymbolLibTable, LIB_ID const& aLibId, int aUnit ) - : m_html( DescriptionFormat ), - m_sym_lib_table( aSymbolLibTable ), - m_lib_id( aLibId ), - m_symbol( nullptr ), - m_unit( aUnit ) + FOOTPRINT_INFO_GENERATOR( SYMBOL_LIB_TABLE* aSymbolLibTable, LIB_ID const& aLibId, int aUnit ) : + m_html( DescriptionFormat ), + m_sym_lib_table( aSymbolLibTable ), + m_lib_id( aLibId ), + m_symbol( nullptr ), + m_unit( aUnit ) { } /** @@ -110,7 +104,6 @@ protected: m_html.Replace( wxS( "__NAME__" ), EscapeHTML( UnescapeString( m_symbol->GetName() ) ) ); } - void SetHtmlAliasOf() { if( m_symbol->IsRoot() ) @@ -130,14 +123,12 @@ protected: root_desc = parent->GetDesc(); } - m_html.Replace( wxS( "__ALIASOF__" ), - wxString::Format( AliasOfFormat, - EscapeHTML( UnescapeString( root_name ) ), - EscapeHTML( root_desc ) ) ); + m_html.Replace( wxS( "__ALIASOF__" ), wxString::Format( AliasOfFormat, + EscapeHTML( UnescapeString( root_name ) ), + EscapeHTML( root_desc ) ) ); } } - void SetHtmlDesc() { wxString esc_desc = EscapeHTML( UnescapeString( m_symbol->GetDescription() ) ); @@ -151,7 +142,6 @@ protected: m_html.Replace( wxS( "__DESC__" ), wxString::Format( DescFormat, esc_desc ) ); } - void SetHtmlKeywords() { wxString keywords = m_symbol->GetKeyWords(); @@ -159,11 +149,9 @@ protected: if( keywords.empty() ) m_html.Replace( wxS( "__KEY__" ), wxEmptyString ); else - m_html.Replace( wxS( "__KEY__" ), - wxString::Format( KeywordsFormat, EscapeHTML( keywords ) ) ); + m_html.Replace( wxS( "__KEY__" ), wxString::Format( KeywordsFormat, EscapeHTML( keywords ) ) ); } - wxString GetHtmlFieldRow( const SCH_FIELD& aField ) const { wxString name = aField.GetCanonicalName(); @@ -263,6 +251,13 @@ protected: m_html.Replace( wxS( "__FIELDS__" ), fieldtable ); } + +private: + wxString m_html; + SYMBOL_LIB_TABLE* m_sym_lib_table; + LIB_ID const m_lib_id; + LIB_SYMBOL* m_symbol; + int m_unit; }; diff --git a/include/design_block_lib_table.h b/include/design_block_lib_table.h index 0c42bd92fe..b839f36c9f 100644 --- a/include/design_block_lib_table.h +++ b/include/design_block_lib_table.h @@ -158,11 +158,13 @@ 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 aThreadSafe if true, do not set LOCALE_IO (which is global). Caller is responsible + * for setting it up correctly. * * @throw IO_ERROR if the library cannot be found, or design block cannot be loaded. */ void DesignBlockEnumerate( wxArrayString& aDesignBlockNames, const wxString& aNickname, - bool aBestEfforts ); + bool aBestEfforts, bool aThreadSafe ); /** * Generate a hashed timestamp representing the last-mod-times of the library indicated @@ -195,10 +197,13 @@ public: * A version of #DesignBlockLoad() for use after #DesignBlockEnumerate() for more efficient * cache management. * + * @param aThreadSafe if true, do not set LOCALE_IO (which is global). Caller is responsible + * for setting it up correctly. + * * 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 DESIGN_BLOCK* GetEnumeratedDesignBlock( const wxString& aNickname, const wxString& aDesignBlockName, + bool aThreadSafe ); /** * The set of return values from DesignBlockSave() below. */ diff --git a/include/footprint_info.h b/include/footprint_info.h index cc15c0a768..6ec1c8127d 100644 --- a/include/footprint_info.h +++ b/include/footprint_info.h @@ -127,11 +127,7 @@ public: friend bool operator<( const FOOTPRINT_INFO& lhs, const FOOTPRINT_INFO& rhs ); protected: - void ensure_loaded() - { - if( !m_loaded ) - load(); - } + void ensure_loaded(); /// lazily load stuff not filled in by constructor. This may throw IO_ERRORS. virtual void load() { }; diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 8f355eebd2..de4b9a8824 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -143,11 +143,13 @@ 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 aThreadSafe if true, do not set LOCALE_IO (which is global). Caller is responsible + * for setting it up correctly. * * @throw IO_ERROR if the library cannot be found, or footprint cannot be loaded. */ void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aNickname, - bool aBestEfforts ); + bool aBestEfforts, bool aThreadSafe ); /** * Generate a hashed timestamp representing the last-mod-times of the library indicated @@ -180,10 +182,14 @@ public: * A version of #FootprintLoad() for use after #FootprintEnumerate() for more efficient * cache management. * + * @param aThreadSafe if true, do not set LOCALE_IO (which is global). Caller is responsible + * for setting it up correctly. + * * 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 wxString& aFootprintName, + bool aThreadSafe ); /** * The set of return values from FootprintSave() below. */ diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 35fd558ae2..220882f678 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -75,7 +75,7 @@ #include #include #include // For ::ResolvePossibleSymlinks() - +#include #include #include @@ -840,6 +840,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in // which prompts the user to continue with overwrite or abort) if( newLibPath.Length() > 0 ) { + LOCALE_IO toggle_locale; IO_RELEASER piSexpr( PCB_IO_MGR::PluginFind( PCB_IO_MGR::KICAD_SEXP ) ); for( FOOTPRINT* footprint : loadedFootprints ) diff --git a/pcbnew/footprint_info_impl.cpp b/pcbnew/footprint_info_impl.cpp index c406962d2c..6d45b09da7 100644 --- a/pcbnew/footprint_info_impl.cpp +++ b/pcbnew/footprint_info_impl.cpp @@ -47,7 +47,7 @@ void FOOTPRINT_INFO_IMPL::load() wxASSERT( fptable ); - const FOOTPRINT* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname ); + const FOOTPRINT* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname, true ); if( footprint == nullptr ) // Should happen only with malformed/broken libraries { @@ -192,7 +192,7 @@ void FOOTPRINT_LIST_IMPL::loadFootprints() CatchErrors( [&]() { - m_lib_table->FootprintEnumerate( fpnames, nickname, false ); + m_lib_table->FootprintEnumerate( fpnames, nickname, false, true ); } ); for( wxString fpname : fpnames ) diff --git a/pcbnew/footprint_libraries_utils.cpp b/pcbnew/footprint_libraries_utils.cpp index c72ca5c936..325863d9e7 100644 --- a/pcbnew/footprint_libraries_utils.cpp +++ b/pcbnew/footprint_libraries_utils.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -691,6 +692,7 @@ void PCB_EDIT_FRAME::ExportFootprintsToLibrary( bool aStoreInNewLib, const wxStr libNickname = row->GetNickName(); } + LOCALE_IO toggle_locale; PCB_IO_MGR::PCB_FILE_T piType = PCB_IO_MGR::KICAD_SEXP; IO_RELEASER pi( PCB_IO_MGR::PluginFind( piType ) ); std::map options { { "skip_cache_validation", "1" } }; // Skip cache validation -- we just created it @@ -1265,7 +1267,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 ); + tbl->FootprintEnumerate( fpnames, aLibName, true, false ); if( !fpnames.empty() ) footprintAttrs = tbl->FootprintLoad( aLibName, fpnames.Last() )->GetAttributes(); diff --git a/pcbnew/footprint_preview_panel.cpp b/pcbnew/footprint_preview_panel.cpp index 95cc770fed..eb406e2376 100644 --- a/pcbnew/footprint_preview_panel.cpp +++ b/pcbnew/footprint_preview_panel.cpp @@ -177,8 +177,8 @@ bool FOOTPRINT_PREVIEW_PANEL::DisplayFootprint( const LIB_ID& aFPID ) try { - const FOOTPRINT* fp = fptbl->GetEnumeratedFootprint( aFPID.GetLibNickname(), - aFPID.GetLibItemName() ); + const FOOTPRINT* fp = fptbl->GetEnumeratedFootprint( aFPID.GetLibNickname(), aFPID.GetLibItemName(), + false ); if( fp ) m_currentFootprint.reset( static_cast( fp->Duplicate( IGNORE_PARENT_GROUP ) ) ); diff --git a/pcbnew/footprint_viewer_frame.cpp b/pcbnew/footprint_viewer_frame.cpp index c15d6bc428..412b646ad1 100644 --- a/pcbnew/footprint_viewer_frame.cpp +++ b/pcbnew/footprint_viewer_frame.cpp @@ -1033,7 +1033,7 @@ void FOOTPRINT_VIEWER_FRAME::SelectAndViewFootprint( FPVIEWER_CONSTANTS aMode ) GetBoard()->RemoveUnusedNets( nullptr ); FOOTPRINT* footprint = PROJECT_PCB::PcbFootprintLibs( &Prj() )->FootprintLoad( getCurNickname(), - getCurFootprintName() ); + getCurFootprintName() ); if( footprint ) displayFootprint( footprint ); diff --git a/pcbnew/generate_footprint_info.cpp b/pcbnew/generate_footprint_info.cpp index 06778a6d85..73525e9a46 100644 --- a/pcbnew/generate_footprint_info.cpp +++ b/pcbnew/generate_footprint_info.cpp @@ -101,18 +101,12 @@ std::optional GetFootprintDocumentationURL( const FOOTPRINT& aFootprin class FOOTPRINT_INFO_GENERATOR { - wxString m_html; - FP_LIB_TABLE* m_fp_lib_table; - LIB_ID const m_lib_id; - - const FOOTPRINT* m_footprint; - public: - FOOTPRINT_INFO_GENERATOR( FP_LIB_TABLE* aFpLibTable, LIB_ID const& aLibId ) - : m_html( DescriptionFormat ), - m_fp_lib_table( aFpLibTable ), - m_lib_id( aLibId ), - m_footprint( nullptr ) + FOOTPRINT_INFO_GENERATOR( FP_LIB_TABLE* aFpLibTable, LIB_ID const& aLibId ) : + m_html( DescriptionFormat ), + m_fp_lib_table( aFpLibTable ), + m_lib_id( aLibId ), + m_footprint( nullptr ) { } /** @@ -128,7 +122,8 @@ public: try { m_footprint = m_fp_lib_table->GetEnumeratedFootprint( m_lib_id.GetLibNickname(), - m_lib_id.GetLibItemName() ); + m_lib_id.GetLibItemName(), + false ); } catch( const IO_ERROR& ioe ) { @@ -183,6 +178,12 @@ public: return m_html; } +private: + wxString m_html; + FP_LIB_TABLE* m_fp_lib_table; + LIB_ID const m_lib_id; + + const FOOTPRINT* m_footprint; }; diff --git a/pcbnew/load_select_footprint.cpp b/pcbnew/load_select_footprint.cpp index b9321713a8..f50f78e28c 100644 --- a/pcbnew/load_select_footprint.cpp +++ b/pcbnew/load_select_footprint.cpp @@ -49,6 +49,7 @@ using namespace std::placeholders; #include #include #include +#include static wxArrayString s_FootprintHistoryList; @@ -334,6 +335,7 @@ bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath ) wxBusyCursor dummy; wxString msg; + LOCALE_IO toggle_locale; PCB_IO_MGR::PCB_FILE_T dstType = PCB_IO_MGR::GuessPluginTypeFromLibPath( dstLibPath ); PCB_IO_MGR::PCB_FILE_T curType = PCB_IO_MGR::GuessPluginTypeFromLibPath( curLibPath ); @@ -363,12 +365,12 @@ bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath ) cur->FootprintEnumerate( footprints, curLibPath, false ); - for( unsigned i = 0; i < footprints.size(); ++i ) + for( const wxString& fp : footprints ) { - const FOOTPRINT* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] ); + const FOOTPRINT* footprint = cur->GetEnumeratedFootprint( curLibPath, fp ); dst->FootprintSave( dstLibPath, footprint ); - msg = wxString::Format( _( "Footprint '%s' saved." ), footprints[i] ); + msg = wxString::Format( _( "Footprint '%s' saved." ), fp ); SetStatusText( msg ); } } diff --git a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.cpp b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.cpp index a2cb180df8..0f932c6fc2 100644 --- a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.cpp +++ b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.cpp @@ -355,9 +355,7 @@ void PCB_IO_EASYEDA::FootprintEnumerate( wxArrayString& aFootprintNames, c_para = doc.head.c_para; if( c_para ) - { packageName = get_def( *c_para, wxS( "package" ), packageName ); - } aFootprintNames.Add( packageName ); } @@ -457,9 +455,8 @@ FOOTPRINT* PCB_IO_EASYEDA::FootprintLoad( const wxString& aLibraryPath, { parts.RemoveAt( 0 ); - FOOTPRINT* footprint = - parser.ParseFootprint( origin, orientation, layer, nullptr, - paramMap, m_loadedFootprints, parts ); + FOOTPRINT* footprint = parser.ParseFootprint( origin, orientation, layer, nullptr, + paramMap, m_loadedFootprints, parts ); if( !footprint ) return nullptr; @@ -502,8 +499,8 @@ FOOTPRINT* PCB_IO_EASYEDA::FootprintLoad( const wxString& aLibraryPath, VECTOR2D origin( doc.head.x, doc.head.y ); - FOOTPRINT* footprint = parser.ParseFootprint( - origin, ANGLE_0, F_Cu, nullptr, *c_para, m_loadedFootprints, doc.shape ); + FOOTPRINT* footprint = parser.ParseFootprint( origin, ANGLE_0, F_Cu, nullptr, *c_para, + m_loadedFootprints, doc.shape ); if( !footprint ) return nullptr; diff --git a/pcbnew/pcb_io/geda/pcb_io_geda.cpp b/pcbnew/pcb_io/geda/pcb_io_geda.cpp index aa9e456f8e..56d20cbe79 100644 --- a/pcbnew/pcb_io/geda/pcb_io_geda.cpp +++ b/pcbnew/pcb_io/geda/pcb_io_geda.cpp @@ -860,7 +860,6 @@ FOOTPRINT* PCB_IO_GEDA::ImportFootprint( const wxString& aFootprintPath, void PCB_IO_GEDA::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath, bool aBestEfforts, const std::map* aProperties ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. wxDir dir( aLibraryPath ); wxString errorMsg; @@ -869,10 +868,7 @@ void PCB_IO_GEDA::FootprintEnumerate( wxArrayString& aFootprintNames, const wxSt if( aBestEfforts ) return; else - { - THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' not found." ), - aLibraryPath ) ); - } + THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' not found." ), aLibraryPath ) ); } init( aProperties ); @@ -902,8 +898,6 @@ const FOOTPRINT* PCB_IO_GEDA::getFootprint( const wxString& aLibraryPath, const std::map* aProperties, bool checkModified ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. - init( aProperties ); validateCache( aLibraryPath, checkModified ); diff --git a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp index 6cce6a4f37..86744451d8 100644 --- a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp +++ b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp @@ -3210,7 +3210,6 @@ void PCB_IO_KICAD_LEGACY::cacheLib( const wxString& aLibraryPath ) void PCB_IO_KICAD_LEGACY::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath, bool aBestEfforts, const std::map* aProperties ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. wxString errorMsg; init( aProperties ); @@ -3236,22 +3235,18 @@ void PCB_IO_KICAD_LEGACY::FootprintEnumerate( wxArrayString& aFootprintNames, co FOOTPRINT* PCB_IO_KICAD_LEGACY::FootprintLoad( const wxString& aLibraryPath, - const wxString& aFootprintName, bool aKeepUUID, - const std::map* aProperties ) + const wxString& aFootprintName, bool aKeepUUID, + const std::map* aProperties ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. - init( aProperties ); cacheLib( aLibraryPath ); - const FOOTPRINT_MAP& footprints = m_cache->m_footprints; + const FOOTPRINT_MAP& footprints = m_cache->m_footprints; FOOTPRINT_MAP::const_iterator it = footprints.find( TO_UTF8( aFootprintName ) ); if( it == footprints.end() ) - { return nullptr; - } // Return copy of already loaded FOOTPRINT FOOTPRINT* copy = (FOOTPRINT*) it->second->Duplicate( IGNORE_PARENT_GROUP ); diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp index 2a0820841d..e2799a39bf 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp @@ -2888,7 +2888,6 @@ void PCB_IO_KICAD_SEXPR::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath, bool aBestEfforts, const std::map* aProperties ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. wxDir dir( aLibPath ); wxString errorMsg; @@ -2919,8 +2918,6 @@ const FOOTPRINT* PCB_IO_KICAD_SEXPR::getFootprint( const wxString& aLibraryPath, const std::map* aProperties, bool checkModified ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. - init( aProperties ); try @@ -3015,8 +3012,6 @@ FOOTPRINT* PCB_IO_KICAD_SEXPR::FootprintLoad( const wxString& aLibraryPath, void PCB_IO_KICAD_SEXPR::FootprintSave( const wxString& aLibraryPath, const FOOTPRINT* aFootprint, const std::map* aProperties ) { - LOCALE_IO toggle; // toggles on, then off, the C locale. - init( aProperties ); // In this public PLUGIN API function, we can safely assume it was @@ -3033,9 +3028,7 @@ void PCB_IO_KICAD_SEXPR::FootprintSave( const wxString& aLibraryPath, const FOOT "Would you like to create it?"), aLibraryPath ); - if( !Pgm().IsGUI() - || wxMessageBox( msg, _( "Library Not Found" ), wxYES_NO | wxICON_QUESTION ) - != wxYES ) + if( !Pgm().IsGUI() || wxMessageBox( msg, _( "Library Not Found" ), wxYES_NO | wxICON_QUESTION ) != wxYES ) return; // Save throws its own IO_ERROR on failure, so no need to recreate here diff --git a/pcbnew/pcb_io/pcb_io_mgr.cpp b/pcbnew/pcb_io/pcb_io_mgr.cpp index 7b142d1d76..618e655f1b 100644 --- a/pcbnew/pcb_io/pcb_io_mgr.cpp +++ b/pcbnew/pcb_io/pcb_io_mgr.cpp @@ -28,7 +28,7 @@ #include #include #include - +#include #include #include @@ -196,6 +196,7 @@ bool PCB_IO_MGR::ConvertLibrary( std::map* aOldFileProps, con if( oldFileType == PCB_IO_MGR::FILE_TYPE_NONE ) return false; + LOCALE_IO toggle_locale; IO_RELEASER oldFilePI( PCB_IO_MGR::PluginFind( oldFileType ) ); IO_RELEASER kicadPI( PCB_IO_MGR::PluginFind( PCB_IO_MGR::KICAD_SEXP ) ); wxArrayString fpNames; @@ -220,8 +221,8 @@ bool PCB_IO_MGR::ConvertLibrary( std::map* aOldFileProps, con for ( const wxString& fpName : fpNames ) { - std::unique_ptr fp( - oldFilePI->GetEnumeratedFootprint( aOldFilePath, fpName, aOldFileProps ) ); + std::unique_ptr fp( oldFilePI->GetEnumeratedFootprint( aOldFilePath, fpName, + aOldFileProps ) ); try { diff --git a/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp b/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp index 9141a58db9..b6399bb0ea 100644 --- a/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp +++ b/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp @@ -392,7 +392,7 @@ wxArrayString GetFootprints( const wxString& aNickName ) if( !tbl ) return footprintNames; - tbl->FootprintEnumerate( footprintNames, aNickName, true ); + tbl->FootprintEnumerate( footprintNames, aNickName, true, false ); return footprintNames; } diff --git a/qa/pcbnew_utils/board_file_utils.cpp b/qa/pcbnew_utils/board_file_utils.cpp index 9a27fae257..81e6fe8562 100644 --- a/qa/pcbnew_utils/board_file_utils.cpp +++ b/qa/pcbnew_utils/board_file_utils.cpp @@ -27,7 +27,7 @@ #include #include #include - +#include #include #include @@ -148,6 +148,7 @@ std::unique_ptr ReadFootprintFromFileOrStream( const std::string& aFi void DumpFootprintToFile( const FOOTPRINT& aFootprint, const std::string& aLibraryPath ) { + LOCALE_IO toggle_locale; PCB_IO_KICAD_SEXPR io; io.FootprintSave( aLibraryPath, &aFootprint, nullptr ); }