From d7563c55c477398c820c54dea33db45d37491743 Mon Sep 17 00:00:00 2001 From: John Beard Date: Tue, 22 Jan 2019 14:47:03 +0000 Subject: [PATCH] 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. --- qa/CMakeLists.txt | 1 + qa/common_tools/main.cpp | 85 +---- qa/pcbnew_tools/CMakeLists.txt | 63 ++++ qa/pcbnew_tools/pcbnew_tools.cpp | 44 +++ qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp | 394 ++++++++++++++++++++ qa/pcbnew_tools/tools/drc_tool/drc_tool.h | 32 ++ qa/qa_utils/CMakeLists.txt | 1 + qa/qa_utils/utility_program.cpp | 115 ++++++ qa/qa_utils/utility_program.h | 53 +++ 9 files changed, 706 insertions(+), 82 deletions(-) create mode 100644 qa/pcbnew_tools/CMakeLists.txt create mode 100644 qa/pcbnew_tools/pcbnew_tools.cpp create mode 100644 qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp create mode 100644 qa/pcbnew_tools/tools/drc_tool/drc_tool.h create mode 100644 qa/qa_utils/utility_program.cpp diff --git a/qa/CMakeLists.txt b/qa/CMakeLists.txt index 1f22f174ab..d132ac030b 100644 --- a/qa/CMakeLists.txt +++ b/qa/CMakeLists.txt @@ -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 ) diff --git a/qa/common_tools/main.cpp b/qa/common_tools/main.cpp index 1733b6184a..c6a6a0d96c 100644 --- a/qa/common_tools/main.cpp +++ b/qa/common_tools/main.cpp @@ -21,13 +21,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#include #include "tools/coroutines/coroutine_tools.h" #include "tools/io_benchmark/io_benchmark.h" -#include - /** * List of registered tools. * @@ -40,86 +38,9 @@ const static std::vector 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 ); } \ No newline at end of file diff --git a/qa/pcbnew_tools/CMakeLists.txt b/qa/pcbnew_tools/CMakeLists.txt new file mode 100644 index 0000000000..04a2c563e7 --- /dev/null +++ b/qa/pcbnew_tools/CMakeLists.txt @@ -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_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 +) \ No newline at end of file diff --git a/qa/pcbnew_tools/pcbnew_tools.cpp b/qa/pcbnew_tools/pcbnew_tools.cpp new file mode 100644 index 0000000000..dbad93da76 --- /dev/null +++ b/qa/pcbnew_tools/pcbnew_tools.cpp @@ -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 + +#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 known_tools = { + &drc_tool, +}; + + +int main( int argc, char** argv ) +{ + COMBINED_UTILITY c_util( known_tools ); + + return c_util.HandleCommandLine( argc, argv ); +} \ No newline at end of file diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp new file mode 100644 index 0000000000..6af5db505d --- /dev/null +++ b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp @@ -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 +#include + +#include + +#include + +// Parsing +#include +#include +#include +#include +#include + +// DRC +#include +#include + +#include +#include + + +/** + * Parse a PCB from the given stream + * + * @param aStream the input stream to read from + */ +std::unique_ptr 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; + + try + { + board.reset( dynamic_cast( 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> markers; + + auto marker_handler = [&]( MARKER_PCB* aMarker ) { + markers.push_back( std::unique_ptr( aMarker ) ); + }; + + std::unique_ptr drc_prov = createDrcProvider( aBoard, marker_handler ); + + DRC_DURATION duration; + { + SCOPED_TIMER 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 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>& 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 createDrcProvider( + BOARD& aBoard, DRC_PROVIDER::MARKER_HANDLER aHandler ) override + { + return std::make_unique( 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 createDrcProvider( + BOARD& aBoard, DRC_PROVIDER::MARKER_HANDLER aHandler ) override + { + return std::make_unique( 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; + + 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, +}; \ No newline at end of file diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.h b/qa/pcbnew_tools/tools/drc_tool/drc_tool.h new file mode 100644 index 0000000000..aa4804994c --- /dev/null +++ b/qa/pcbnew_tools/tools/drc_tool/drc_tool.h @@ -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 + +/// A tool to run DRC tools on KiCad PCBs from the command line +extern UTILITY_PROGRAM drc_tool; + +#endif //PCBNEW_TOOLS_DRC_TOOL_H \ No newline at end of file diff --git a/qa/qa_utils/CMakeLists.txt b/qa/qa_utils/CMakeLists.txt index d04a622d57..bc04b72cad 100644 --- a/qa/qa_utils/CMakeLists.txt +++ b/qa/qa_utils/CMakeLists.txt @@ -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 diff --git a/qa/qa_utils/utility_program.cpp b/qa/qa_utils/utility_program.cpp new file mode 100644 index 0000000000..0da346e4d2 --- /dev/null +++ b/qa/qa_utils/utility_program.cpp @@ -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 + + +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 ); +} \ No newline at end of file diff --git a/qa/qa_utils/utility_program.h b/qa/qa_utils/utility_program.h index e9708f8737..b862bbe625 100644 --- a/qa/qa_utils/utility_program.h +++ b/qa/qa_utils/utility_program.h @@ -25,6 +25,9 @@ #define UTILITY_PROGRAM_H #include +#include +#include +#include /** * 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; + + 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 \ No newline at end of file