diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index cc0a9f7aa4..3748e02ea4 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -61,7 +61,8 @@ DRC::DRC() : PCB_TOOL_BASE( "pcbnew.DRCTool" ), m_pcbEditorFrame( nullptr ), m_pcb( nullptr ), - m_drcDialog( nullptr ) + m_drcDialog( nullptr ), + m_rulesFileLastMod( 0 ) { // establish initial values for everything: m_doPad2PadTest = true; // enable pad to pad clearance tests @@ -98,7 +99,7 @@ void DRC::Reset( RESET_REASON aReason ) m_pcb = m_pcbEditorFrame->GetBoard(); - readRules(); + loadRules(); } } @@ -354,35 +355,51 @@ int DRC::TestZoneToZoneOutlines() } -void DRC::readRules() +void DRC::loadRules() { - wxString rulesFilepath = m_pcbEditorFrame->Prj().AbsolutePath( "drc-rules" ); + wxString rulesFilepath = m_pcbEditorFrame->Prj().AbsolutePath( "drc-rules" ); + wxFileName rulesFile( rulesFilepath ); - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); - bds.m_DRCRuleSelectors.clear(); - bds.m_DRCRules.clear(); - - FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); - - if( fp ) + if( rulesFile.FileExists() ) { - try + wxLongLong lastMod = rulesFile.GetModificationTime().GetValue(); + + if( lastMod > m_rulesFileLastMod ) { - DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); - parser.Parse( bds.m_DRCRuleSelectors, bds.m_DRCRules ); - } - catch( PARSE_ERROR& pe ) - { - DisplayError( m_drcDialog, pe.What() ); + m_rulesFileLastMod = lastMod; + m_ruleSelectors.clear(); + m_rules.clear(); + + FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); + + if( fp ) + { + try + { + DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); + parser.Parse( m_ruleSelectors, m_rules ); + } + catch( PARSE_ERROR& pe ) + { + // Don't leave possibly malformed stuff around for us to trip over + m_ruleSelectors.clear(); + m_rules.clear(); + + DisplayError( m_drcDialog, pe.What() ); + } + } } } + + BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); + bds.m_DRCRuleSelectors = m_ruleSelectors; + bds.m_DRCRules = m_rules; } void DRC::RunTests( wxTextCtrl* aMessages ) { - // TODO: timestamp file and read only if newer - readRules(); + loadRules(); // be sure m_pcb is the current board, not a old one // ( the board can be reloaded ) diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 235e8dc0a6..52ee614fbf 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -159,15 +159,19 @@ private: bool m_reportAllTrackErrors; // Report all tracks errors (or only 4 first errors) bool m_testFootprints; // Test footprints against schematic - PCB_EDIT_FRAME* m_pcbEditorFrame; // The pcb frame editor which owns the board - BOARD* m_pcb; - SHAPE_POLY_SET m_board_outlines; // The board outline including cutouts - DIALOG_DRC* m_drcDialog; + PCB_EDIT_FRAME* m_pcbEditorFrame; // The pcb frame editor which owns the board + BOARD* m_pcb; + SHAPE_POLY_SET m_board_outlines; // The board outline including cutouts + DIALOG_DRC* m_drcDialog; - std::vector m_unconnected; // list of unconnected pads - std::vector m_footprints; // list of footprint warnings - bool m_drcRun; - bool m_footprintsTested; + std::vector m_unconnected; // list of unconnected pads + std::vector m_footprints; // list of footprint warnings + bool m_drcRun; + bool m_footprintsTested; + + wxLongLong m_rulesFileLastMod; + std::vector m_ruleSelectors; + std::vector m_rules; ///> Sets up handlers for various events. void setTransitions() override; @@ -177,7 +181,7 @@ private: */ void updatePointers(); - void readRules(); + void loadRules(); EDA_UNITS userUnits() const { return m_pcbEditorFrame->GetUserUnits(); } diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index 0a7a8d5ca5..7f722103a2 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -96,7 +96,17 @@ void DRC_RULES_PARSER::Parse( std::vector& aSelectors, ruleMap[ rule->m_Name ] = rule; for( const std::pair& entry : selectorRules ) - entry.first->m_Rule = ruleMap[ entry.second ]; + { + if( ruleMap.count( entry.second ) ) + { + entry.first->m_Rule = ruleMap[ entry.second ]; + } + else + { + wxString errText = wxString::Format( _( "Rule \"%s\" not found." ), entry.second ); + THROW_PARSE_ERROR( errText, CurSource(), "", 0, 0 ); + } + } }