KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_easypc.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 The KiCad Developers, see AUTHORS.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, see <https://www.gnu.org/licenses/>.
18 */
19
23
27
28#include <ki_exception.h>
29#include <lib_id.h>
30#include <lib_symbol.h>
31#include <progress_reporter.h>
32#include <project.h>
33#include <sch_screen.h>
34#include <sch_sheet.h>
35#include <sch_sheet_path.h>
36#include <schematic.h>
37#include <string_utils.h>
39
40#include <wx/filename.h>
41
42
44 SCH_IO( wxS( "Easy-PC / DesignSpark Schematic" ) )
45{
47}
48
49
51
52
53bool SCH_IO_EASYPC::CanReadSchematicFile( const wxString& aFileName ) const
54{
55 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
56 return false;
57
59 return info.IsProject || info.FileKind == EASYPC::FILE_KIND::SCHEMATIC_DESIGN;
60}
61
62
63bool SCH_IO_EASYPC::CanReadLibrary( const wxString& aFileName ) const
64{
65 if( !SCH_IO::CanReadLibrary( aFileName ) )
66 return false;
67
69
72}
73
74
75SCH_IO_EASYPC::LIBRARY& SCH_IO_EASYPC::library( const wxString& aLibraryPath )
76{
77 const long long stamp = EASYPC::LIBRARY_FILE::Timestamp( aLibraryPath );
78 auto it = m_libraries.find( aLibraryPath );
79
80 if( it != m_libraries.end() && it->second.Timestamp == stamp )
81 return it->second;
82
83 if( it != m_libraries.end() )
84 m_libraries.erase( it );
85
86 std::unique_ptr<EASYPC::LIBRARY_FILE> file = std::make_unique<EASYPC::LIBRARY_FILE>( aLibraryPath );
87 LIBRARY& lib = m_libraries[aLibraryPath];
88
89 for( const wxString& warning : file->Warnings() )
90 m_reporter->Report( warning, RPT_SEVERITY_WARNING );
91
92 lib.Timestamp = stamp;
93 lib.File = std::move( file );
94 return lib;
95}
96
97
98void SCH_IO_EASYPC::EnumerateSymbolLib( wxArrayString& aSymbolNameList, const wxString& aLibraryPath,
99 const std::map<std::string, UTF8>* aProperties )
100{
101 // KiCad names carry the characters a LIB_ID forbids escaped, and LoadSymbol takes them back the same way
102 for( const wxString& name : library( aLibraryPath ).File->ItemNames() )
103 aSymbolNameList.Add( EscapeString( name, CTX_LIBID ) );
104}
105
106
107void SCH_IO_EASYPC::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList, const wxString& aLibraryPath,
108 const std::map<std::string, UTF8>* aProperties )
109{
110 for( const wxString& name : library( aLibraryPath ).File->ItemNames() )
111 {
112 if( LIB_SYMBOL* symbol = LoadSymbol( aLibraryPath, EscapeString( name, CTX_LIBID ) ) )
113 aSymbolList.push_back( symbol );
114 }
115}
116
117
120 const std::vector<const EASYPC::SOURCE_PCB_COMPONENT*>& aPackages )
121{
122 std::vector<EASYPC::SOURCE_GATE*> gates = EASYPC::TypedItems<EASYPC::SOURCE_GATE>( aScm.Gates );
123
124 for( size_t g = 0; g < gates.size(); ++g )
125 {
126 for( int t = 0; t < static_cast<int>( gates[g]->PinNames.size() ); ++t )
127 {
128 EASYPC::GATE_TERMINAL first = EASYPC::ResolveTerminal( aPackages.front(), static_cast<int>( g ), t );
129
130 for( const EASYPC::SOURCE_PCB_COMPONENT* pcb : aPackages )
131 {
132 EASYPC::GATE_TERMINAL other = EASYPC::ResolveTerminal( pcb, static_cast<int>( g ), t );
133
134 if( other.Mapped != first.Mapped || other.Number != first.Number )
135 return false;
136 }
137 }
138 }
139
140 return true;
141}
142
143
144std::unique_ptr<LIB_SYMBOL> SCH_IO_EASYPC::convertComponent( const LIBRARY& aLib, const wxString& aLibraryPath,
145 const wxString& aName )
146{
147 std::unique_ptr<EASYPC::LIBRARY_ITEM> item = aLib.File->LoadItem( aName );
148 std::vector<const EASYPC::SOURCE_PCB_COMPONENT*> packages;
150
151 for( const EASYPC::LIBRARY_STREAM& stream : item->Streams )
152 {
153 if( const EASYPC::SOURCE_SCM_COMPONENT* scm = dynamic_cast<const EASYPC::SOURCE_SCM_COMPONENT*>( stream.Item ) )
154 src.Schematic = scm;
155 }
156
157 if( !src.Schematic )
158 {
160 wxString::Format( _( "Easy-PC component '%s' in '%s' has no schematic part" ), aName, aLibraryPath ) );
161 }
162
163 for( const EASYPC::LIBRARY_STREAM& stream : item->Streams )
164 {
165 const EASYPC::SOURCE_PCB_COMPONENT* pcb = dynamic_cast<const EASYPC::SOURCE_PCB_COMPONENT*>( stream.Item );
166
167 if( !pcb )
168 continue;
169
170 // A package with no library names its footprint only, which LIB_ID allows
171 const wxString nickname = wxFileName( pcb->Library, wxPATH_WIN ).GetName();
172 const wxString footprint = nickname.IsEmpty() ? pcb->Symbol : nickname + wxS( ":" ) + pcb->Symbol;
173
174 packages.push_back( pcb );
175 src.FootprintFilters.Add( footprint );
176
177 // A component whose named default package is missing has no default footprint
178 if( stream.StreamName == src.Schematic->Package )
179 {
180 src.Board = pcb;
181 src.Footprint = footprint;
182 }
183 }
184
185 // Without a default package the pin numbers stand when every package numbers every gate pin alike
186 if( !src.Board && !packages.empty() )
187 {
188 if( packagesAgree( *src.Schematic, packages ) )
189 {
190 src.Board = packages.front();
191 }
192 else
193 {
194 m_reporter->Report( wxString::Format( _( "Easy-PC component '%s' in '%s' has no default package and its "
195 "packages number the pins differently; its pins are left "
196 "unnumbered." ),
197 aName, aLibraryPath ),
199 }
200 }
201
202 // Gate symbols live in other libraries; each loaded item stays alive until the conversion is done
203 std::vector<std::unique_ptr<EASYPC::LIBRARY_ITEM>> gateItems;
204 const wxString cmlName = wxFileName( aLibraryPath ).GetFullName();
205 int gateNumber = 0;
206
207 for( const EASYPC::OBJECT* obj : EASYPC::ListItems( src.Schematic->Gates ) )
208 {
209 const EASYPC::SOURCE_GATE* gate = dynamic_cast<const EASYPC::SOURCE_GATE*>( obj );
210 ++gateNumber;
211
212 if( !gate )
213 {
214 THROW_IO_ERROR( wxString::Format( _( "Easy-PC component '%s' in '%s' has an empty gate slot" ), aName,
215 aLibraryPath ) );
216 }
217
218 // Stored absolute paths may name another machine; resolve the filename beside this library.
219 const wxString sslName = wxFileName( gate->Library, wxPATH_WIN ).GetFullName();
220 const wxString sslPath = EASYPC::ResolveProjectItem( aLibraryPath, sslName );
221 const EASYPC::SOURCE_SYMBOL* symbol = nullptr;
222 wxString msg;
223
224 if( !wxFileName::FileExists( sslPath ) )
225 {
226 msg = wxString::Format( _( "Component '%s': gate %d symbol library '%s' not found beside '%s'." ), aName,
227 gateNumber, sslName, cmlName );
228 }
229 else
230 {
231 try
232 {
233 gateItems.push_back( library( sslPath ).File->LoadItem( gate->Symbol ) );
234
235 if( !gateItems.back()->Streams.empty() )
236 symbol = dynamic_cast<const EASYPC::SOURCE_SYMBOL*>( gateItems.back()->Streams.front().Item );
237
238 if( !symbol )
239 {
240 msg = wxString::Format( _( "Component '%s': gate %d item '%s' in '%s' is not a symbol." ), aName,
241 gateNumber, gate->Symbol, sslName );
242 }
243 }
244 catch( const IO_ERROR& e )
245 {
246 msg = wxString::Format( _( "Component '%s': gate %d symbol '%s' could not be loaded from '%s' "
247 "(%s)." ),
248 aName, gateNumber, gate->Symbol, sslName, e.What() );
249 }
250 }
251
252 if( !symbol )
253 {
254 m_reporter->Report( msg, RPT_SEVERITY_WARNING );
255 THROW_IO_ERROR( msg );
256 }
257
258 src.Gates.push_back( symbol );
259 }
260
261 LIB_ID id( wxFileName( aLibraryPath ).GetName(), EscapeString( aName, CTX_LIBID ) );
262 return EASYPC::ConvertComponentSymbol( src, id );
263}
264
265
266LIB_SYMBOL* SCH_IO_EASYPC::LoadSymbol( const wxString& aLibraryPath, const wxString& aPartName,
267 const std::map<std::string, UTF8>* aProperties )
268{
269 LIBRARY& lib = library( aLibraryPath );
270
271 if( auto it = lib.Symbols.find( aPartName ); it != lib.Symbols.end() )
272 return it->second.get();
273
274 const wxString item = UnescapeString( aPartName );
275
276 if( !lib.File->HasItem( item ) )
277 return nullptr;
278
279 std::unique_ptr<LIB_SYMBOL> symbol;
280
281 // lib is passed on, since looking the library up again could reload it and leave lib dangling
283 {
284 symbol = convertComponent( lib, aLibraryPath, item );
285 }
287 {
288 std::unique_ptr<EASYPC::LIBRARY_ITEM> loaded = lib.File->LoadItem( item );
289 const EASYPC::SOURCE_SYMBOL* sym = nullptr;
290
291 if( !loaded->Streams.empty() )
292 sym = dynamic_cast<const EASYPC::SOURCE_SYMBOL*>( loaded->Streams.front().Item );
293
294 if( !sym )
295 {
297 wxString::Format( _( "Easy-PC library item '%s' in '%s' is not a symbol" ), item, aLibraryPath ) );
298 }
299
300 LIB_ID id( wxFileName( aLibraryPath ).GetName(), EscapeString( item, CTX_LIBID ) );
301 symbol = EASYPC::ConvertSymbol( *sym, id );
302 }
303 else
304 {
305 THROW_IO_ERROR( wxString::Format( _( "'%s' is not an Easy-PC symbol or component library" ), aLibraryPath ) );
306 }
307
308 LIB_SYMBOL* result = symbol.get();
309 lib.Symbols[aPartName] = std::move( symbol );
310 return result;
311}
312
313
314SCH_SHEET* SCH_IO_EASYPC::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic, SCH_SHEET* aAppendToMe,
315 const std::map<std::string, UTF8>* aProperties )
316{
317 wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr );
318
319 // Without a sheet to fill, the load would replace the live top-level sheets
320 if( !aAppendToMe && aProperties && aProperties->count( "hierarchical_sheet_load" ) )
321 {
322 THROW_IO_ERROR( wxString::Format( _( "'%s' is a complete Easy-PC schematic and cannot be loaded as a "
323 "hierarchical sheet. Use File > Import > Non-KiCad Schematic... "
324 "instead." ),
325 aFileName ) );
326 }
327
329 {
330 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
331
332 if( !m_progressReporter->KeepRefreshing() )
334 }
335
336 std::vector<wxString> paths;
337
338 if( wxFileName( aFileName ).GetExt().CmpNoCase( wxS( "prj" ) ) == 0 )
339 {
340 std::unique_ptr<EASYPC::PROJECT_DOCUMENT> prj = EASYPC::LoadProject( aFileName );
341 for( const EASYPC::SOURCE_PROJECT_ITEM* item : prj->Project->Schematics )
342 paths.push_back( EASYPC::ResolveProjectItem( aFileName, item->Name ) );
343
344 if( paths.empty() )
345 THROW_IO_ERROR( wxString::Format( _( "Project '%s' contains no schematics" ), aFileName ) );
346 }
347 else
348 {
349 paths.push_back( aFileName );
350 }
351
352 std::vector<std::unique_ptr<EASYPC::DESIGN_DOCUMENT>> docs;
353 std::vector<const EASYPC::DESIGN_DOCUMENT*> allDocs;
355
356 for( const wxString& path : paths )
357 {
358 docs.push_back( EASYPC::LoadDesign( path ) );
359 allDocs.push_back( docs.back().get() );
360
361 if( docs.back()->Kind != EASYPC::DOC_KIND::SCHEMATIC )
362 THROW_IO_ERROR( wxString::Format( _( "'%s' is not a schematic design" ), path ) );
363
364 names.AddSheet( *docs.back() );
365 }
366
367 if( aAppendToMe )
368 {
369 wxCHECK_MSG( aSchematic->IsValid(), nullptr, wxS( "Can't append to a schematic with no root!" ) );
370
371 if( docs.size() != 1 )
372 {
373 THROW_IO_ERROR( wxString::Format( _( "'%s' holds %zu schematics; only one can be appended to a sheet" ),
374 aFileName, docs.size() ) );
375 }
376
377 if( !aAppendToMe->GetScreen() )
378 {
379 wxFileName fn( paths.front() );
381
382 aAppendToMe->SetScreen( new SCH_SCREEN( aSchematic ) );
383 aAppendToMe->GetScreen()->SetFileName( fn.GetFullPath() );
384 aAppendToMe->SyncUuidToScreen();
385 }
386 }
387
388 // A real UUID, unlike the virtual root's nil one, so SetTopLevelSheets() keeps it
389 SCH_SHEET* rootSheet = aAppendToMe ? aAppendToMe : new SCH_SHEET( aSchematic );
390
391 if( !aAppendToMe )
392 aSchematic->SetTopLevelSheets( { rootSheet } );
393
394 std::vector<SCH_SHEET*> sheets;
395 EASYPC::SCH_BUILDER builder( aSchematic, names, m_reporter );
396
397 builder.SetProjectSymbols( allDocs );
398
399 // Every sheet of a project is a top-level KiCad sheet; no known file holds a block (hierarchical) symbol
400 for( size_t i = 0; i < docs.size(); ++i )
401 {
402 SCH_SHEET* sheet = sheets.empty() ? rootSheet : new SCH_SHEET( &aSchematic->Root() );
404 path.push_back( sheet );
405 sheets.push_back( sheet );
406
407 // The sheet appended to keeps its own name, file and page
408 if( sheet != aAppendToMe )
409 {
410 wxFileName fn( paths[i] );
412
413 sheet->SetScreen( new SCH_SCREEN( aSchematic ) );
414 sheet->GetScreen()->SetFileName( fn.GetFullPath() );
415 sheet->SetFileName( fn.GetFullName() );
416 sheet->SetName( wxFileName( paths[i] ).GetName() );
417
418 path.SetPageNumber( wxString::Format( wxS( "%zu" ), i + 1 ) );
419 sheet->GetScreen()->SetPageNumber( wxString::Format( wxS( "%zu" ), i + 1 ) );
420 }
421
422 builder.BuildSheet( *docs[i], sheet, path );
423 }
424
425 if( aAppendToMe )
426 {
427 aSchematic->RefreshHierarchy();
428 return aAppendToMe;
429 }
430
431 aSchematic->SetTopLevelSheets( sheets );
432 aSchematic->RefreshHierarchy();
433
434 // The foreign-import path does not create per-sheet instance data, so references would not resolve
435 wxString projectName = aSchematic->Project().GetProjectName();
436
437 if( projectName.IsEmpty() )
438 projectName = wxFileName( aFileName ).GetName();
439
440 SCH_SHEET_LIST list = aSchematic->BuildUnorderedSheetList();
441 list.AddNewSymbolInstances( SCH_SHEET_PATH(), projectName );
442 list.AddNewSheetInstances( SCH_SHEET_PATH(), 0 );
443
444 return rootSheet;
445}
const char * name
void SetPageNumber(const wxString &aPageNumber)
Definition base_screen.h:75
std::unique_ptr< LIBRARY_ITEM > LoadItem(const wxString &aItemName) const
Throws IO_ERROR if no item has that name.
bool HasItem(const wxString &aItemName) const
FILE_KIND Kind() const
static long long Timestamp(const wxString &aPath)
A library file's modification time, 0 when it does not exist.
void BuildSheet(const DESIGN_DOCUMENT &aDoc, SCH_SHEET *aSheet, const SCH_SHEET_PATH &aSheetPath)
void SetProjectSymbols(const std::vector< const DESIGN_DOCUMENT * > &aDocs)
Symbols of every sheet, for gates placed on a sheet other than the one being built.
Project-wide net naming: a user name takes the spelling of its first occurrence.
void AddSheet(const DESIGN_DOCUMENT &aDoc)
const wxString & GetName() const
Return a brief hard coded name for this IO interface.
Definition io_base.h:79
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition io_base.h:238
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition io_base.h:241
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition io_base.cpp:71
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
Define a library symbol object.
Definition lib_symbol.h:114
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:195
Holds all the data relating to one schematic.
Definition schematic.h:149
SCH_SHEET_LIST BuildUnorderedSheetList() const
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:171
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition schematic.h:289
void SetTopLevelSheets(const std::vector< SCH_SHEET * > &aSheets)
Replace the top level sheets, rebuilding the hierarchy and connectivity around them.
SCH_SHEET & Root() const
Definition schematic.h:200
void RefreshHierarchy()
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
LIBRARY & library(const wxString &aLibraryPath)
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
bool CanReadSchematicFile(const wxString &aFileName) const override
Checks if this SCH_IO can read the specified schematic file.
std::unique_ptr< LIB_SYMBOL > convertComponent(const LIBRARY &aLib, const wxString &aLibraryPath, const wxString &aName)
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aPartName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Converted on first use and owned by the plugin until the file changes.
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
std::map< wxString, LIBRARY > m_libraries
virtual bool CanReadSchematicFile(const wxString &aFileName) const
Checks if this SCH_IO can read the specified schematic file.
Definition sch_io.cpp:47
SCH_IO(const wxString &aName)
Definition sch_io.h:406
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this list of sheet paths prefixed with aPrefix...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:392
void SyncUuidToScreen()
Take the identity of the screen this sheet owns.
void SetName(const wxString &aName)
Definition sch_sheet.h:143
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
static REPORTER & GetInstance()
Definition reporter.cpp:324
Symbols, components and gates, embedded in designs or the single object of a library item stream.
The project file (.prj), a bare archive stream.
Loading designs, library items and projects.
Builds KiCad sheets from Easy-PC / DesignSpark schematic designs.
Schematic graphics, texts and symbols shared by the sheet builder and the symbol libraries,...
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_CANCELLED()
static const std::string KiCadSchematicFileExtension
FILE_INFO Probe(const wxString &aPath)
Identify a file; projects are parsed fully, while designs and libraries are only inspected....
GATE_TERMINAL ResolveTerminal(const SOURCE_PCB_COMPONENT *aPcb, int aGate, int aTerminal)
Terminal aTerminal (0-based) of gate aGate; formats before 9000 map a bare pad number,...
std::unique_ptr< LIB_SYMBOL > ConvertComponentSymbol(const SCH_COMPONENT_SOURCE &aSrc, const LIB_ID &aId)
One unit per gate in symbol-local coordinates, zero-length passive pins at the pads,...
std::unique_ptr< DESIGN_DOCUMENT > LoadDesign(const wxString &aPath)
std::unique_ptr< LIB_SYMBOL > ConvertSymbol(const SOURCE_SYMBOL &aSymbol, const LIB_ID &aId)
A .ssl symbol alone: one unit, pins numbered by pad number.
std::vector< T * > TypedItems(const OBJECT *aList)
The items of ListItems that are a T, in order.
wxString ResolveProjectItem(const wxString &aProjectPath, const wxString &aItemName)
The file a project item names, as Easy-PC opens it: the Windows path relative to the project's direct...
const std::vector< OBJECT * > & ListItems(const OBJECT *aList)
The items of a design list or array, empty for anything else.
std::unique_ptr< PROJECT_DOCUMENT > LoadProject(const wxString &aPath)
@ RPT_SEVERITY_WARNING
static bool packagesAgree(const EASYPC::SOURCE_SCM_COMPONENT &aScm, const std::vector< const EASYPC::SOURCE_PCB_COMPONENT * > &aPackages)
Whether every package gives every gate terminal the same pin number.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
What a package's gate map says about one gate terminal.
wxString Number
KiCad pin number, stacked notation for a pad list.
OBJECT * Item
what the stream's single ReadObject returned
Root of every deserialized object.
Everything one component LIB_SYMBOL is made from.
std::vector< const SOURCE_SYMBOL * > Gates
symbol per gate; null leaves that unit empty
const SOURCE_SCM_COMPONENT * Schematic
const SOURCE_PCB_COMPONENT * Board
the package whose gate map numbers the pins
A schematic symbol and its pin names.
The package half of a component.
wxString Name
Windows path relative to the project directory.
Footprints and schematic symbols alike.
std::unique_ptr< EASYPC::LIBRARY_FILE > File
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > Symbols
std::string path
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.