KiCad PCB EDA Suite
pcb_parser_tool.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
25 
26 #include <cstdio>
27 #include <string>
28 
29 #include <common.h>
30 #include <profile.h>
31 
32 #include <wx/cmdline.h>
33 
34 #include <board_item.h>
37 #include <richio.h>
38 
39 #include <wx/cmdline.h>
40 
43 
44 
45 using PARSE_DURATION = std::chrono::microseconds;
46 
47 
54 bool parse( std::istream& aStream, bool aVerbose )
55 {
56  // Take input from stdin
58  reader.SetStream( aStream );
59 
60  PCB_PARSER parser;
61 
62  parser.SetLineReader( &reader );
63 
64  BOARD_ITEM* board = nullptr;
65 
66  PARSE_DURATION duration{};
67 
68  try
69  {
70  PROF_COUNTER timer;
71  board = parser.Parse();
72 
73  duration = timer.SinceStart<PARSE_DURATION>();
74  }
75  catch( const IO_ERROR& )
76  {
77  }
78 
79  if( aVerbose )
80  {
81  std::cout << "Took: " << duration.count() << "us" << std::endl;
82  }
83 
84  return board != nullptr;
85 }
86 
87 
88 static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
89  { wxCMD_LINE_SWITCH, "h", "help", _( "displays help on the command line parameters" ).mb_str(),
90  wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
91  { wxCMD_LINE_SWITCH, "v", "verbose", _( "print parsing information" ).mb_str() },
92  { wxCMD_LINE_PARAM, nullptr, nullptr, _( "input file" ).mb_str(), wxCMD_LINE_VAL_STRING,
93  wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE },
94  { wxCMD_LINE_NONE }
95 };
96 
97 
99 {
101 };
102 
103 
104 int pcb_parser_main_func( int argc, char** argv )
105 {
106 #ifdef __AFL_COMPILER
107  __AFL_INIT();
108 #endif
109 
110  wxMessageOutput::Set( new wxMessageOutputStderr );
111  wxCmdLineParser cl_parser( argc, argv );
112  cl_parser.SetDesc( g_cmdLineDesc );
113  cl_parser.AddUsageText(
114  _( "This program parses PCB files, either from the "
115  "stdin stream or from the given filenames. This can be used either for "
116  "standalone testing of the parser or for fuzz testing." ) );
117 
118  int cmd_parsed_ok = cl_parser.Parse();
119  if( cmd_parsed_ok != 0 )
120  {
121  // Help and invalid input both stop here
122  return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
123  }
124 
125  const bool verbose = cl_parser.Found( "verbose" );
126 
127  bool ok = true;
128 
129  const auto file_count = cl_parser.GetParamCount();
130 
131  if( file_count == 0 )
132  {
133  // Parse the file provided on stdin - used by AFL to drive the
134  // program
135  // while (__AFL_LOOP(2))
136  {
137  ok = parse( std::cin, verbose );
138  }
139  }
140  else
141  {
142  // Parse 'n' files given on the command line
143  // (this is useful for input minimisation (e.g. afl-tmin) as
144  // well as manual testing
145  for( unsigned i = 0; i < file_count; i++ )
146  {
147  const auto filename = cl_parser.GetParam( i ).ToStdString();
148 
149  if( verbose )
150  std::cout << "Parsing: " << filename << std::endl;
151 
152  std::ifstream fin;
153  fin.open( filename );
154 
155  ok = ok && parse( fin, verbose );
156  }
157  }
158 
159  if( !ok )
161 
162  return KI_TEST::RET_CODES::OK;
163 }
164 
165 
167  { "pcb_parser", "Parse a KiCad PCB file", pcb_parser_main_func } );
Tools can define their own statuses from here onwards.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
Definition: board_item.h:86
PCB_PARSER reads a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD...
Definition: pcb_parser.h:69
#define OK
bool parse(std::istream &aStream, bool aVerbose)
Parse a PCB or footprint file from the given input stream.
The command line was not correct for the tool.
static bool registered
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:44
void SetStream(std::istream &aStream)
Set the stream for this line reader.
static bool Register(const KI_TEST::UTILITY_PROGRAM &aProgInfo)
Register a utility program factory function against an ID string.
LINE_READER that wraps a given std::istream instance.
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:473
static const wxCmdLineEntryDesc g_cmdLineDesc[]
std::chrono::microseconds PARSE_DURATION
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one,...
Definition: pcb_parser.h:352
int pcb_parser_main_func(int argc, char **argv)
#define _(s)
Definition: 3d_actions.cpp:33
The common library.
DURATION SinceStart(bool aSinceLast=false)
Definition: profile.h:129
Pcbnew s-expression file format parser definition.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
PARSER_RET_CODES
Definition: sexpr_parse.cpp:99