From 9bd7ea815caa673cdeba192c38ff43d4c4510105 Mon Sep 17 00:00:00 2001 From: John Beard Date: Thu, 24 Jan 2019 14:56:55 +0000 Subject: [PATCH] QA: Centralise BOARD reading functions in pcbnew_utils Several pcbnew_tools utilities read a file from the command line. Instead of replicating this code, centralise the code in qa_pcbnew_utils, which allows simpler reuse. THe utilities are: * polygon_triangulation * polygon_generator * drc_tool pcb_parser keeps its own function, as that is the focus of the tool, and its likely to have its own instrumention. This also adds the ability to read from stdin for the above tools, which means fuzz testers could theoretically work with them, and it also can make life easier if you can pipe a board to the executable directly. --- qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp | 62 ++----------------- .../polygon_generator/polygon_generator.cpp | 46 ++++++-------- .../polygon_triangulation.cpp | 43 ++++--------- qa/pcbnew_utils/CMakeLists.txt | 4 +- qa/pcbnew_utils/board_file_utils.cpp | 48 ++++++++++++++ .../include/pcbnew_utils/board_file_utils.h | 35 ++++++++++- 6 files changed, 120 insertions(+), 118 deletions(-) diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp index 060da344be..28b3acd93b 100644 --- a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp +++ b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp @@ -30,12 +30,7 @@ #include -// Parsing -#include -#include -#include -#include -#include +#include // DRC #include @@ -45,36 +40,6 @@ #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; /** @@ -330,31 +295,14 @@ int drc_main_func( int argc, char** argv ) const bool verbose = cl_parser.Found( "verbose" ); - const auto file_count = cl_parser.GetParamCount(); + std::string filename; - std::unique_ptr board; - - if( file_count == 0 ) + if( cl_parser.GetParamCount() ) { - // Parse the file provided on stdin - used by AFL to drive the - // program - // while (__AFL_LOOP(2)) - { - board = parse( std::cin ); - } + filename = cl_parser.GetParam( 0 ).ToStdString(); } - 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 ); - } + std::unique_ptr board = KI_TEST::ReadBoardFromFileOrStream( filename ); if( !board ) return PARSER_RET_CODES::PARSE_FAILED; diff --git a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp index 593314392b..8aba10b90a 100644 --- a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp +++ b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp @@ -29,8 +29,7 @@ #include #include -#include -#include +#include #include #include @@ -39,26 +38,6 @@ #include #include -BOARD* loadBoard( const std::string& filename ) -{ - PLUGIN::RELEASER pi( new PCB_IO ); - BOARD* brd = nullptr; - - try - { - brd = pi->Load( wxString( filename.c_str() ), NULL, NULL ); - } - catch( const IO_ERROR& ioe ) - { - wxString msg = wxString::Format( _( "Error loading board.\n%s" ), ioe.Problem() ); - - printf( "%s\n", (const char*) msg.mb_str() ); - return nullptr; - } - - return brd; -} - void process( const BOARD_CONNECTED_ITEM* item, int net ) { @@ -79,19 +58,32 @@ void process( const BOARD_CONNECTED_ITEM* item, int net ) } +enum POLY_GEN_RET_CODES +{ + LOAD_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC, +}; + + int polygon_gererator_main( int argc, char* argv[] ) { if( argc < 2 ) { printf( "A sample tool for dumping board geometry as a set of polygons.\n" ); - printf( "usage : %s board_file.kicad_pcb\n\n", argv[0] ); - return -1; + printf( "Usage : %s board_file.kicad_pcb\n\n", argv[0] ); + return KI_TEST::RET_CODES::BAD_CMDLINE; } - std::unique_ptr brd( loadBoard( argv[1] ) ); + std::string filename; + + if( argc > 1 ) + filename = argv[1]; + + auto brd = KI_TEST::ReadBoardFromFileOrStream( filename ); if( !brd ) - return -1; + { + return POLY_GEN_RET_CODES::LOAD_FAILED; + } for( unsigned net = 0; net < brd->GetNetCount(); net++ ) { @@ -112,7 +104,7 @@ int polygon_gererator_main( int argc, char* argv[] ) printf( "endnet\n" ); } - return 0; + return KI_TEST::RET_CODES::OK; } /* diff --git a/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp index d10af9a6b7..7f9924393e 100644 --- a/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp +++ b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp @@ -24,11 +24,10 @@ #include "polygon_triangulation.h" -#include #include +#include -#include -#include +#include #include #include @@ -200,26 +199,6 @@ aResult->clear(); std::swap( (*aResult) [0], (*aResult)[outline] ); } -BOARD* loadBoardTri( const std::string& filename ) -{ - PLUGIN::RELEASER pi( new PCB_IO ); - BOARD* brd = nullptr; - - try - { - brd = pi->Load( wxString( filename.c_str() ), NULL, NULL ); - } - catch( const IO_ERROR& ioe ) - { - wxString msg = wxString::Format( _( "Error loading board.\n%s" ), - ioe.Problem() ); - - printf( "%s\n", (const char*) msg.mb_str() ); - return nullptr; - } - - return brd; -} enum POLY_TRI_RET_CODES { @@ -229,7 +208,12 @@ enum POLY_TRI_RET_CODES int polygon_triangulation_main( int argc, char *argv[] ) { - auto brd = loadBoardTri( argc > 1 ? argv[1] : "../../../../tests/dp.kicad_pcb" ); + std::string filename; + + if( argc > 1 ) + filename = argv[1]; + + auto brd = KI_TEST::ReadBoardFromFileOrStream( filename ); if( !brd ) return POLY_TRI_RET_CODES::LOAD_FAILED; @@ -244,8 +228,7 @@ int polygon_triangulation_main( int argc, char *argv[] ) size_t parallelThreadCount = std::max( std::thread::hardware_concurrency(), 2 ); for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { - std::thread t = std::thread( [brd, &zonesToTriangulate, &threadsFinished] () - { + std::thread t = std::thread( [&brd, &zonesToTriangulate, &threadsFinished]() { for( size_t areaId = zonesToTriangulate.fetch_add( 1 ); areaId < static_cast( brd->GetAreaCount() ); areaId = zonesToTriangulate.fetch_add( 1 ) ) @@ -257,7 +240,7 @@ int polygon_triangulation_main( int argc, char *argv[] ) (void) poly; printf("zone %zu/%d\n", ( areaId + 1 ), brd->GetAreaCount() ); - #if 0 +#if 0 PROF_COUNTER unfrac("unfrac"); poly.Unfracture( SHAPE_POLY_SET::PM_FAST ); unfrac.Show(); @@ -269,7 +252,7 @@ int polygon_triangulation_main( int argc, char *argv[] ) poly.triangulatePoly( &poly.Polygon(i) ); } triangulate.Show(); - #endif +#endif } threadsFinished++; @@ -281,13 +264,9 @@ int polygon_triangulation_main( int argc, char *argv[] ) while( threadsFinished < parallelThreadCount ) std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - cnt.Show(); - delete brd; - return KI_TEST::RET_CODES::OK; - } /* diff --git a/qa/pcbnew_utils/CMakeLists.txt b/qa/pcbnew_utils/CMakeLists.txt index f67eb70111..e2316d2efe 100644 --- a/qa/pcbnew_utils/CMakeLists.txt +++ b/qa/pcbnew_utils/CMakeLists.txt @@ -54,7 +54,9 @@ target_include_directories( qa_pcbnew_utils PUBLIC ${INC_AFTER} ) -# target_link_libraries( qa_pcbnew_utils PUBLIC +target_link_libraries( qa_pcbnew_utils PUBLIC + qa_utils +) # 3d-viewer # connectivity # pcbcommon diff --git a/qa/pcbnew_utils/board_file_utils.cpp b/qa/pcbnew_utils/board_file_utils.cpp index c278c22edb..d4969ae91b 100644 --- a/qa/pcbnew_utils/board_file_utils.cpp +++ b/qa/pcbnew_utils/board_file_utils.cpp @@ -30,6 +30,8 @@ #include +#include + namespace KI_TEST { @@ -50,4 +52,50 @@ std::unique_ptr ReadBoardItemFromFile( const std::string& aFilename return std::unique_ptr( parser.Parse() ); } + +std::unique_ptr ReadBoardItemFromStream( 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( parser.Parse() ); + } + catch( const IO_ERROR& parse_error ) + { + std::cerr << parse_error.Problem() << std::endl; + std::cerr << parse_error.Where() << std::endl; + } + + return board; +} + +std::unique_ptr ReadBoardFromFileOrStream( + const std::string& aFilename, std::istream& aFallback ) +{ + std::istream* in_stream = nullptr; + std::ifstream file_stream; + + if( aFilename.empty() ) + { + // no file, read stdin + in_stream = &aFallback; + } + else + { + file_stream.open( aFilename ); + in_stream = &file_stream; + } + + return ReadItemFromStream( *in_stream ); +} + } // namespace KI_TEST \ No newline at end of file diff --git a/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h b/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h index 8543487fd0..4f39b9fbdf 100644 --- a/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h +++ b/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h @@ -25,6 +25,7 @@ #ifndef QA_PCBNEW_UTILS_BOARD_FILE_UTILS__H #define QA_PCBNEW_UTILS_BOARD_FILE_UTILS__H +#include #include #include @@ -60,7 +61,39 @@ void DumpBoardToFile( BOARD& aBoard, const std::string& aFilename ); * @param aFilename the file to read in * @returns a new #BOARD_ITEM, which is nullptr if the read or parse failed. */ -std::unique_ptr ReadBoardItemFromFile( const std::string& aFilename ); +std::unique_ptr ReadBoardItemFromStream( std::istream& aStream ); + +/** + * Read a specific kind of #BOARD_ITEM from a stream + * + * @tparam ITEM the item type to return (probably a #MODULE or #BOARD) + * @param aStream the stream to read from. + */ +template std::unique_ptr ReadItemFromStream( std::istream& aStream ) +{ + auto bi_ptr = ReadBoardItemFromStream( aStream ); + std::unique_ptr downcast_ptr; + + // if it's the right type, downcast and "steal" (and we'll return ownership) + ITEM* const tmp = dynamic_cast( bi_ptr.get() ); + if( tmp != nullptr ) + { + bi_ptr.release(); + downcast_ptr.reset( tmp ); + } + + return downcast_ptr; +} + +/** + * Read a board from a file, or another stream, as appropriate + * + * @param aFilename The file to read, or the fallback if empty + * @param aFallback: the fallback stream + * @return a #BOARD, if successful + */ +std::unique_ptr ReadBoardFromFileOrStream( + const std::string& aFilename, std::istream& aFallback = std::cin ); } // namespace KI_TEST