QA: Pcbnew utility tools: DRC tool
Add a tool that allows a user to run DRC functions on a given KiCad PCB file. The first available functions are the courtyard functions. Also move most of the utility program logic into qa_util for better reusability.
This commit is contained in:
parent
8297ab24e4
commit
d7563c55c4
|
@ -25,6 +25,7 @@ add_subdirectory( shape_poly_set_refactor )
|
|||
|
||||
# Utility/debugging/profiling programs
|
||||
add_subdirectory( common_tools )
|
||||
add_subdirectory( pcbnew_tools )
|
||||
add_subdirectory( pcb_parse_input )
|
||||
|
||||
# add_subdirectory( pcb_test_window )
|
||||
|
|
|
@ -21,13 +21,11 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <utility_program.h>
|
||||
|
||||
#include "tools/coroutines/coroutine_tools.h"
|
||||
#include "tools/io_benchmark/io_benchmark.h"
|
||||
|
||||
#include <wx/cmdline.h>
|
||||
|
||||
/**
|
||||
* List of registered tools.
|
||||
*
|
||||
|
@ -40,86 +38,9 @@ const static std::vector<UTILITY_PROGRAM*> known_tools = {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Print the names and descriptions of the registered tools
|
||||
*/
|
||||
static void show_tool_list()
|
||||
{
|
||||
for( const auto& tool : known_tools )
|
||||
{
|
||||
std::cout << tool->m_name << ": \t" << tool->m_desc << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the utility program that matches a tool name
|
||||
* @param aName the name to look for
|
||||
* @return the tool function
|
||||
*/
|
||||
UTILITY_PROGRAM::FUNC* get_program( const std::string& aName )
|
||||
{
|
||||
for( const auto& tool : known_tools )
|
||||
{
|
||||
if( tool->m_name == aName )
|
||||
return &tool->m_func;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void print_usage( char* name )
|
||||
{
|
||||
std::cout << "Run a utility tool." << std::endl;
|
||||
|
||||
std::cout << "Usage: " << name << " [-h] [-l] [TOOL [TOOL_OPTIONS]]" << std::endl;
|
||||
|
||||
std::cout << " -h show this message and exit." << std::endl
|
||||
<< " -l print known tools and exit." << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "Known tools: " << std::endl;
|
||||
|
||||
show_tool_list();
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
wxMessageOutput::Set( new wxMessageOutputStderr );
|
||||
COMBINED_UTILITY c_util( known_tools );
|
||||
|
||||
// Need at least one parameter
|
||||
if( argc < 2 )
|
||||
{
|
||||
print_usage( argv[0] );
|
||||
return RET_CODES::BAD_CMDLINE;
|
||||
}
|
||||
|
||||
const std::string arg1( argv[1] );
|
||||
|
||||
if( argc == 2 )
|
||||
{
|
||||
if( arg1 == "-h" )
|
||||
{
|
||||
print_usage( argv[0] );
|
||||
return RET_CODES::OK;
|
||||
}
|
||||
else if( arg1 == "-l" )
|
||||
{
|
||||
show_tool_list();
|
||||
return RET_CODES::OK;
|
||||
}
|
||||
}
|
||||
|
||||
auto func = get_program( arg1 );
|
||||
|
||||
if( !func )
|
||||
{
|
||||
std::cout << "Tool " << arg1 << " not found." << std::endl;
|
||||
return RET_CODES::UNKNOWN_TOOL;
|
||||
}
|
||||
|
||||
// pass on the rest of the commands
|
||||
return ( *func )( argc - 1, argv + 1 );
|
||||
return c_util.HandleCommandLine( argc, argv );
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
# This program source code file is part of KiCad, a free EDA CAD application.
|
||||
#
|
||||
# Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, you may find one here:
|
||||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# or you may search the http://www.gnu.org website for the version 2 license,
|
||||
# or you may write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
|
||||
if( BUILD_GITHUB_PLUGIN )
|
||||
set( GITHUB_PLUGIN_LIBRARIES github_plugin )
|
||||
endif()
|
||||
|
||||
add_executable( qa_pcbnew_tools
|
||||
|
||||
# The main entry point
|
||||
pcbnew_tools.cpp
|
||||
|
||||
tools/drc_tool/drc_tool.cpp
|
||||
|
||||
# Older CMakes cannot link OBJECT libraries
|
||||
# https://cmake.org/pipermail/cmake/2013-November/056263.html
|
||||
$<TARGET_OBJECTS:pcbnew_kiface_objects>
|
||||
)
|
||||
|
||||
target_link_libraries( qa_pcbnew_tools
|
||||
qa_pcbnew_utils
|
||||
3d-viewer
|
||||
connectivity
|
||||
pcbcommon
|
||||
pnsrouter
|
||||
pcad2kicadpcb
|
||||
bitmaps
|
||||
common
|
||||
pcbcommon
|
||||
legacy_wx
|
||||
polygon
|
||||
bitmaps
|
||||
gal
|
||||
qa_utils
|
||||
lib_dxf
|
||||
idf3
|
||||
unit_test_utils
|
||||
${wxWidgets_LIBRARIES}
|
||||
${GITHUB_PLUGIN_LIBRARIES}
|
||||
${GDI_PLUS_LIBRARIES}
|
||||
${PYTHON_LIBRARIES}
|
||||
${Boost_LIBRARIES} # must follow GITHUB
|
||||
${PCBNEW_EXTRA_LIBS} # -lrt must follow Boost
|
||||
)
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <utility_program.h>
|
||||
|
||||
#include "tools/drc_tool/drc_tool.h"
|
||||
|
||||
/**
|
||||
* List of registered tools.
|
||||
*
|
||||
* This is a pretty rudimentary way to register, but for a simple purpose,
|
||||
* it's effective enough. When you have a new tool, add it to this list.
|
||||
*/
|
||||
const static std::vector<UTILITY_PROGRAM*> known_tools = {
|
||||
&drc_tool,
|
||||
};
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
COMBINED_UTILITY c_util( known_tools );
|
||||
|
||||
return c_util.HandleCommandLine( argc, argv );
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "drc_tool.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <wx/cmdline.h>
|
||||
|
||||
// Parsing
|
||||
#include <class_board.h>
|
||||
#include <class_board_item.h>
|
||||
#include <kicad_plugin.h>
|
||||
#include <pcb_parser.h>
|
||||
#include <richio.h>
|
||||
|
||||
// DRC
|
||||
#include <drc/courtyard_overlap.h>
|
||||
#include <drc/drc_marker_factory.h>
|
||||
|
||||
#include <scoped_timer.h>
|
||||
#include <stdstream_line_reader.h>
|
||||
|
||||
|
||||
/**
|
||||
* Parse a PCB from the given stream
|
||||
*
|
||||
* @param aStream the input stream to read from
|
||||
*/
|
||||
std::unique_ptr<BOARD> parse( std::istream& aStream )
|
||||
{
|
||||
// Take input from stdin
|
||||
STDISTREAM_LINE_READER reader;
|
||||
reader.SetStream( aStream );
|
||||
|
||||
PCB_PARSER parser;
|
||||
|
||||
parser.SetLineReader( &reader );
|
||||
|
||||
std::unique_ptr<BOARD> board;
|
||||
|
||||
try
|
||||
{
|
||||
board.reset( dynamic_cast<BOARD*>( parser.Parse() ) );
|
||||
}
|
||||
catch( const IO_ERROR& parse_error )
|
||||
{
|
||||
std::cerr << parse_error.Problem() << std::endl;
|
||||
std::cerr << parse_error.Where() << std::endl;
|
||||
}
|
||||
|
||||
return board;
|
||||
}
|
||||
|
||||
using DRC_DURATION = std::chrono::microseconds;
|
||||
|
||||
/**
|
||||
* DRC runner: provides a simple framework to run some DRC checks on #BOARDS.
|
||||
* The DRC_RUNNER can be set up as needed to instantiate a #DRC_PROVIDER to
|
||||
* perform the desired DRC on the #BOARD and provide some basic information
|
||||
* about what happened.
|
||||
*/
|
||||
class DRC_RUNNER
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* How the DRC runner behaves (e.g. what is printed and how)
|
||||
*/
|
||||
struct EXECUTION_CONTEXT
|
||||
{
|
||||
bool m_verbose;
|
||||
bool m_print_times;
|
||||
bool m_print_markers;
|
||||
};
|
||||
|
||||
DRC_RUNNER( const EXECUTION_CONTEXT& aExecCtx ) : m_exec_context( aExecCtx )
|
||||
{
|
||||
}
|
||||
|
||||
void Execute( BOARD& aBoard )
|
||||
{
|
||||
if( m_exec_context.m_verbose )
|
||||
{
|
||||
std::cout << "Running DRC check: " << getRunnerIntro() << std::endl;
|
||||
}
|
||||
|
||||
aBoard.SetDesignSettings( getDesignSettings() );
|
||||
|
||||
std::vector<std::unique_ptr<MARKER_PCB>> markers;
|
||||
|
||||
auto marker_handler = [&]( MARKER_PCB* aMarker ) {
|
||||
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
|
||||
};
|
||||
|
||||
std::unique_ptr<DRC_PROVIDER> drc_prov = createDrcProvider( aBoard, marker_handler );
|
||||
|
||||
DRC_DURATION duration;
|
||||
{
|
||||
SCOPED_TIMER<DRC_DURATION> timer( duration );
|
||||
drc_prov->RunDRC( aBoard );
|
||||
}
|
||||
|
||||
// report results
|
||||
if( m_exec_context.m_print_times )
|
||||
reportDuration( duration );
|
||||
|
||||
if( m_exec_context.m_print_markers )
|
||||
reportMarkers( markers );
|
||||
}
|
||||
|
||||
protected:
|
||||
const DRC_MARKER_FACTORY& getMarkerFactory() const
|
||||
{
|
||||
return m_marker_factory;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get the introduction text for this DRC runner
|
||||
*/
|
||||
virtual std::string getRunnerIntro() const = 0;
|
||||
|
||||
/**
|
||||
* Get suitable design settings for this DRC runner
|
||||
*/
|
||||
virtual BOARD_DESIGN_SETTINGS getDesignSettings() const = 0;
|
||||
|
||||
virtual std::unique_ptr<DRC_PROVIDER> createDrcProvider(
|
||||
BOARD& aBoard, DRC_PROVIDER::MARKER_HANDLER aHandler ) = 0;
|
||||
|
||||
void reportDuration( const DRC_DURATION& aDuration ) const
|
||||
{
|
||||
std::cout << "Took: " << aDuration.count() << "us" << std::endl;
|
||||
}
|
||||
|
||||
void reportMarkers( const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers ) const
|
||||
{
|
||||
std::cout << "DRC markers: " << aMarkers.size() << std::endl;
|
||||
|
||||
int index = 0;
|
||||
for( const auto& m : aMarkers )
|
||||
{
|
||||
std::cout << index++ << ": " << m->GetReporter().ShowReport( EDA_UNITS_T::MILLIMETRES );
|
||||
}
|
||||
|
||||
if( index )
|
||||
{
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
const EXECUTION_CONTEXT m_exec_context;
|
||||
DRC_MARKER_FACTORY m_marker_factory;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* DRC runner to run only DRC courtyard-overlap checks
|
||||
*/
|
||||
class DRC_COURTYARD_OVERLAP_RUNNER : public DRC_RUNNER
|
||||
{
|
||||
public:
|
||||
DRC_COURTYARD_OVERLAP_RUNNER( const EXECUTION_CONTEXT& aCtx ) : DRC_RUNNER( aCtx )
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::string getRunnerIntro() const override
|
||||
{
|
||||
return "Courtyard overlap";
|
||||
}
|
||||
|
||||
BOARD_DESIGN_SETTINGS getDesignSettings() const override
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS des_settings;
|
||||
des_settings.m_RequireCourtyards = false;
|
||||
des_settings.m_ProhibitOverlappingCourtyards = true;
|
||||
|
||||
return des_settings;
|
||||
}
|
||||
|
||||
std::unique_ptr<DRC_PROVIDER> createDrcProvider(
|
||||
BOARD& aBoard, DRC_PROVIDER::MARKER_HANDLER aHandler ) override
|
||||
{
|
||||
return std::make_unique<DRC_COURTYARD_OVERLAP>( getMarkerFactory(), aHandler );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* DRC runner to run only DRC courtyard-missing checks
|
||||
*/
|
||||
class DRC_COURTYARD_MISSING_RUNNER : public DRC_RUNNER
|
||||
{
|
||||
public:
|
||||
DRC_COURTYARD_MISSING_RUNNER( const EXECUTION_CONTEXT& aCtx ) : DRC_RUNNER( aCtx )
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::string getRunnerIntro() const override
|
||||
{
|
||||
return "Courtyard missing";
|
||||
}
|
||||
|
||||
BOARD_DESIGN_SETTINGS getDesignSettings() const override
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS des_settings;
|
||||
des_settings.m_RequireCourtyards = true;
|
||||
des_settings.m_ProhibitOverlappingCourtyards = false;
|
||||
|
||||
return des_settings;
|
||||
}
|
||||
|
||||
std::unique_ptr<DRC_PROVIDER> createDrcProvider(
|
||||
BOARD& aBoard, DRC_PROVIDER::MARKER_HANDLER aHandler ) override
|
||||
{
|
||||
return std::make_unique<DRC_COURTYARD_OVERLAP>( getMarkerFactory(), aHandler );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"h",
|
||||
"help",
|
||||
_( "displays help on the command line parameters" ).mb_str(),
|
||||
wxCMD_LINE_VAL_NONE,
|
||||
wxCMD_LINE_OPTION_HELP,
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"v",
|
||||
"verbose",
|
||||
_( "print parsing information" ).mb_str(),
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"t",
|
||||
"timings",
|
||||
_( "print DRC timings" ).mb_str(),
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"m",
|
||||
"print-markers",
|
||||
_( "print DRC marker information" ).mb_str(),
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"A",
|
||||
"all-checks",
|
||||
_( "perform all available DRC checks" ).mb_str(),
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"C",
|
||||
"courtyard-overlap",
|
||||
_( "perform courtyard-overlap (and malformation) checking" ).mb_str(),
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_SWITCH,
|
||||
"c",
|
||||
"courtyard-missing",
|
||||
_( "perform courtyard-missing checking" ).mb_str(),
|
||||
},
|
||||
{
|
||||
wxCMD_LINE_PARAM,
|
||||
nullptr,
|
||||
nullptr,
|
||||
_( "input file" ).mb_str(),
|
||||
wxCMD_LINE_VAL_STRING,
|
||||
wxCMD_LINE_PARAM_OPTIONAL,
|
||||
},
|
||||
{ wxCMD_LINE_NONE }
|
||||
};
|
||||
|
||||
/**
|
||||
* Tool=specific return codes
|
||||
*/
|
||||
enum PARSER_RET_CODES
|
||||
{
|
||||
PARSE_FAILED = RET_CODES::TOOL_SPECIFIC,
|
||||
};
|
||||
|
||||
|
||||
int drc_main_func( int argc, char** argv )
|
||||
{
|
||||
#ifdef __AFL_COMPILER
|
||||
__AFL_INIT();
|
||||
#endif
|
||||
|
||||
wxMessageOutput::Set( new wxMessageOutputStderr );
|
||||
wxCmdLineParser cl_parser( argc, argv );
|
||||
cl_parser.SetDesc( g_cmdLineDesc );
|
||||
cl_parser.AddUsageText(
|
||||
_( "This program runs DRC tools on given PCB files. "
|
||||
"This can be used for debugging, fuzz testing or development, etc." ) );
|
||||
|
||||
int cmd_parsed_ok = cl_parser.Parse();
|
||||
if( cmd_parsed_ok != 0 )
|
||||
{
|
||||
// Help and invalid input both stop here
|
||||
return ( cmd_parsed_ok == -1 ) ? RET_CODES::OK : RET_CODES::BAD_CMDLINE;
|
||||
}
|
||||
|
||||
const bool verbose = cl_parser.Found( "verbose" );
|
||||
|
||||
const auto file_count = cl_parser.GetParamCount();
|
||||
|
||||
std::unique_ptr<BOARD> board;
|
||||
|
||||
if( file_count == 0 )
|
||||
{
|
||||
// Parse the file provided on stdin - used by AFL to drive the
|
||||
// program
|
||||
// while (__AFL_LOOP(2))
|
||||
{
|
||||
board = parse( std::cin );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto filename = cl_parser.GetParam( 0 ).ToStdString();
|
||||
|
||||
if( verbose )
|
||||
std::cout << "Parsing: " << filename << std::endl;
|
||||
|
||||
std::ifstream fin;
|
||||
fin.open( filename );
|
||||
|
||||
board = parse( fin );
|
||||
}
|
||||
|
||||
if( !board )
|
||||
return PARSER_RET_CODES::PARSE_FAILED;
|
||||
|
||||
DRC_RUNNER::EXECUTION_CONTEXT exec_context{
|
||||
verbose,
|
||||
cl_parser.Found( "timings" ),
|
||||
cl_parser.Found( "print-markers" ),
|
||||
};
|
||||
|
||||
const bool all = cl_parser.Found( "all-checks" );
|
||||
|
||||
// Run the DRC on the board
|
||||
if( all || cl_parser.Found( "courtyard-overlap" ) )
|
||||
{
|
||||
DRC_COURTYARD_OVERLAP_RUNNER runner( exec_context );
|
||||
runner.Execute( *board );
|
||||
}
|
||||
|
||||
if( all || cl_parser.Found( "courtyard-missing" ) )
|
||||
{
|
||||
DRC_COURTYARD_MISSING_RUNNER runner( exec_context );
|
||||
runner.Execute( *board );
|
||||
}
|
||||
|
||||
return RET_CODES::OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Define the tool interface
|
||||
*/
|
||||
UTILITY_PROGRAM drc_tool = {
|
||||
"drc",
|
||||
"Run selected DRC function on a PCB",
|
||||
drc_main_func,
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef PCBNEW_TOOLS_DRC_TOOL_H
|
||||
#define PCBNEW_TOOLS_DRC_TOOL_H
|
||||
|
||||
#include <utility_program.h>
|
||||
|
||||
/// A tool to run DRC tools on KiCad PCBs from the command line
|
||||
extern UTILITY_PROGRAM drc_tool;
|
||||
|
||||
#endif //PCBNEW_TOOLS_DRC_TOOL_H
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
set( QA_UTIL_COMMON_SRC
|
||||
stdstream_line_reader.cpp
|
||||
utility_program.cpp
|
||||
)
|
||||
|
||||
# A generic library of useful functions for various testing purposes
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include "utility_program.h"
|
||||
|
||||
#include <wx/msgout.h>
|
||||
|
||||
|
||||
COMBINED_UTILITY::COMBINED_UTILITY( const UTIL_LIST& aSubUtils ) : m_subUtils( aSubUtils )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print the names and descriptions of the registered tools
|
||||
*/
|
||||
void COMBINED_UTILITY::showSubUtilityList( std::ostream& os ) const
|
||||
{
|
||||
for( const auto& tool : m_subUtils )
|
||||
{
|
||||
os << tool->m_name << ": \t" << tool->m_desc << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the utility program that matches a tool name
|
||||
* @param aName the name to look for
|
||||
* @return the tool function
|
||||
*/
|
||||
UTILITY_PROGRAM::FUNC* COMBINED_UTILITY::findSubUtility( const std::string& aName ) const
|
||||
{
|
||||
for( const auto& tool : m_subUtils )
|
||||
{
|
||||
if( tool->m_name == aName )
|
||||
return &tool->m_func;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void COMBINED_UTILITY::printUsage( char* name, std::ostream& os ) const
|
||||
{
|
||||
os << "Run a utility tool." << std::endl;
|
||||
|
||||
os << "Usage: " << name << " [-h] [-l] [TOOL [TOOL_OPTIONS]]" << std::endl;
|
||||
|
||||
os << " -h show this message and exit." << std::endl
|
||||
<< " -l print known tools and exit." << std::endl;
|
||||
|
||||
os << std::endl;
|
||||
os << "Known tools: " << std::endl;
|
||||
|
||||
showSubUtilityList( os );
|
||||
}
|
||||
|
||||
|
||||
int COMBINED_UTILITY::HandleCommandLine( int argc, char** argv ) const
|
||||
{
|
||||
wxMessageOutput::Set( new wxMessageOutputStderr );
|
||||
|
||||
// Need at least one parameter
|
||||
if( argc < 2 )
|
||||
{
|
||||
printUsage( argv[0], std::cerr );
|
||||
return RET_CODES::BAD_CMDLINE;
|
||||
}
|
||||
|
||||
const std::string arg1( argv[1] );
|
||||
|
||||
if( argc == 2 )
|
||||
{
|
||||
if( arg1 == "-h" )
|
||||
{
|
||||
printUsage( argv[0], std::cout );
|
||||
return RET_CODES::OK;
|
||||
}
|
||||
else if( arg1 == "-l" )
|
||||
{
|
||||
showSubUtilityList( std::cout );
|
||||
return RET_CODES::OK;
|
||||
}
|
||||
}
|
||||
|
||||
auto func = findSubUtility( arg1 );
|
||||
|
||||
if( !func )
|
||||
{
|
||||
std::cerr << "Tool " << arg1 << " not found." << std::endl;
|
||||
return RET_CODES::UNKNOWN_TOOL;
|
||||
}
|
||||
|
||||
// pass on the rest of the commands
|
||||
return ( *func )( argc - 1, argv + 1 );
|
||||
}
|
|
@ -25,6 +25,9 @@
|
|||
#define UTILITY_PROGRAM_H
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Return codes for tools
|
||||
|
@ -74,4 +77,54 @@ struct UTILITY_PROGRAM
|
|||
FUNC m_func;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class that handles delegation of command lines to one of a
|
||||
* number of "sub-utilities"
|
||||
*/
|
||||
class COMBINED_UTILITY
|
||||
{
|
||||
public:
|
||||
using UTIL_LIST = std::vector<UTILITY_PROGRAM*>;
|
||||
|
||||
COMBINED_UTILITY( const UTIL_LIST& aSubUtils );
|
||||
|
||||
/**
|
||||
* Take in a a command line and:
|
||||
*
|
||||
* * Handle "top level" commands like -h and -l
|
||||
* * Delegate to sub-utilities
|
||||
* * Report malformed command lines
|
||||
*
|
||||
* @param argc argument count (directly from the main() parameter )
|
||||
* @param argv argument values (directly from the main() parameter )
|
||||
* @return return code
|
||||
*/
|
||||
int HandleCommandLine( int argc, char** argv ) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Format the list of known sub-utils.
|
||||
* @param os the stream to format on
|
||||
*/
|
||||
void showSubUtilityList( std::ostream& os ) const;
|
||||
|
||||
/**
|
||||
* Find a sub-utility with the given ID/name.
|
||||
* @param aName the desired sub-utility name (e.g. "drc")
|
||||
* @return pointer to the function that runs that sub-utility
|
||||
*/
|
||||
UTILITY_PROGRAM::FUNC* findSubUtility( const std::string& aName ) const;
|
||||
|
||||
/**
|
||||
* Print the command line usage of this program
|
||||
* @param name the name the program was run with
|
||||
* @param os stream to print to
|
||||
*/
|
||||
void printUsage( char* name, std::ostream& os ) const;
|
||||
|
||||
/// List of known sub-utils
|
||||
const UTIL_LIST& m_subUtils;
|
||||
};
|
||||
|
||||
#endif // UTILITY_PROGRAM_H
|
Loading…
Reference in New Issue