KiCad PCB EDA Suite
Loading...
Searching...
No Matches
common/netlist_reader/netlist_reader.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
20
21
22#include <string_utils.h>
23#include <reporter.h>
24#include <richio.h>
25
27#include <netlist_reader/netlist_reader.h>
28
29#include <wx/regex.h>
30
31
37
38
40{
41 // Orcad Pcb2 netlist format starts by "( {", followed by an unknown comment,
42 // depending on the tool which created the file
43 wxRegEx reOrcad( wxT( "(?i)[ ]*\\([ \t]+{+" ), wxRE_ADVANCED );
44 wxASSERT( reOrcad.IsValid() );
45
46 // Our legacy netlist format starts by "# EESchema Netlist "
47 wxRegEx reLegacy( wxT( "(?i)#[ \t]+EESchema[ \t]+Netlist[ \t]+" ), wxRE_ADVANCED );
48 wxASSERT( reLegacy.IsValid() );
49
50 // Our new netlist format starts by "(export (version "
51 wxRegEx reKicad( wxT( "[ ]*\\(export(\\s+\\(version)?" ), wxRE_ADVANCED );
52 wxASSERT( reKicad.IsValid() );
53
54 wxString line;
55
56 while( aLineReader->ReadLine() )
57 {
58 line = From_UTF8( aLineReader->Line() );
59
60 if( reLegacy.Matches( line ) )
61 return LEGACY;
62 else if( reKicad.Matches( line ) )
63 return KICAD;
64 else if( reOrcad.Matches( line ) )
65 return ORCAD;
66 }
67
68 return UNKNOWN;
69}
70
71
73 const wxString& aNetlistFileName,
74 const wxString& aCompFootprintFileName )
75{
76 wxASSERT( aNetlist != nullptr );
77
78 std::unique_ptr<FILE_LINE_READER> file_rdr =
79 std::make_unique<FILE_LINE_READER>( aNetlistFileName );
80
81 NETLIST_FILE_T type = GuessNetlistFileType( file_rdr.get() );
82 file_rdr->Rewind();
83
84 // The component footprint link reader is NULL if no file name was specified.
85 std::unique_ptr<CMP_READER> cmp_rdr( aCompFootprintFileName.IsEmpty() ?
86 nullptr :
87 new CMP_READER( new FILE_LINE_READER( aCompFootprintFileName ) ) );
88
89 switch( type )
90 {
91 case LEGACY:
92 case ORCAD:
93 return new LEGACY_NETLIST_READER( file_rdr.release(), aNetlist, cmp_rdr.release() );
94
95 case KICAD:
96 return new KICAD_NETLIST_READER( file_rdr.release(), aNetlist, cmp_rdr.release() );
97
98 default: // Unrecognized format:
99 break;
100 }
101
102 return nullptr;
103}
104
105
107{
108 if( m_lineReader )
109 {
110 delete m_lineReader;
111 m_lineReader = nullptr;
112 }
113}
114
115
116bool CMP_READER::Load( NETLIST* aNetlist )
117{
118 wxCHECK_MSG( aNetlist != nullptr, true, wxT( "No netlist passed to CMP_READER::Load()" ) );
119
120 wxString reference; // Stores value read from line like Reference = BUS1;
121 wxString timestamp; // Stores value read from line like TimeStamp = /32307DE2/AA450F67;
122 wxString footprint; // Stores value read from line like IdModule = CP6;
123 wxString buffer;
124 wxString value;
125
126 bool ok = true;
127
128 while( m_lineReader->ReadLine() )
129 {
130 buffer = From_UTF8( m_lineReader->Line() );
131
132 if( !buffer.StartsWith( wxT( "BeginCmp" ) ) )
133 continue;
134
135 // Begin component description.
136 reference.Empty();
137 footprint.Empty();
138 timestamp.Empty();
139
140 while( m_lineReader->ReadLine() )
141 {
142 buffer = From_UTF8( m_lineReader->Line() );
143
144 if( buffer.StartsWith( wxT( "EndCmp" ) ) )
145 break;
146
147 // store string value, stored between '=' and ';' delimiters.
148 value = buffer.AfterFirst( '=' );
149 value = value.BeforeLast( ';' );
150 value.Trim( true );
151 value.Trim( false );
152
153 if( buffer.StartsWith( wxT( "Reference" ) ) )
154 {
155 reference = value;
156 continue;
157 }
158
159 if( buffer.StartsWith( wxT( "IdModule =" ) ) )
160 {
161 footprint = value;
162 continue;
163 }
164
165 if( buffer.StartsWith( wxT( "TimeStamp =" ) ) )
166 {
167 timestamp = value;
168 continue;
169 }
170 }
171
172 // Find the corresponding item in component list:
173 COMPONENT* component = aNetlist->GetComponentByReference( reference );
174
175 // The corresponding component could no longer existing in the netlist. This
176 // can happen when it is removed from schematic and still exists in footprint
177 // assignment list. This is an usual case during the life of a design.
178 if( component )
179 {
180 LIB_ID fpid;
181
182 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
183 {
184 wxString error;
185 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d" ),
186 m_lineReader->GetSource(), m_lineReader->LineNumber() );
187
188 THROW_IO_ERROR( error );
189 }
190
191 // For checking purpose, store the existing LIB_ID (if any) in the alternate fpid copy
192 // if this existing LIB_ID differs from the LIB_ID read from the .cmp file.
193 // CvPcb can ask for user to chose the right LIB_ID.
194 // It happens if the LIB_ID was modified outside CvPcb.
195 if( fpid != component->GetFPID() && !component->GetFPID().empty() )
196 component->SetAltFPID( component->GetFPID() );
197
198 component->SetFPID( fpid );
199 }
200 else
201 {
202 ok = false; // can be used to display a warning in Pcbnew.
203 }
204 }
205
206 return ok;
207}
Read a component footprint link file (*.cmp) format.
LINE_READER * m_lineReader
The line reader to read.
bool Load(NETLIST *aNetlist)
Read the *.cmp file format contains the component footprint assignments created by CvPcb into aNetlis...
Store all of the related component information found in a netlist.
void SetAltFPID(const LIB_ID &aFPID)
void SetFPID(const LIB_ID &aFPID)
const LIB_ID & GetFPID() const
A LINE_READER that reads from an open file.
Definition richio.h:154
Read the new s-expression based KiCad netlist format.
Read the KiCad legacy and the old Orcad netlist formats.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:48
bool empty() const
Definition lib_id.h:189
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition richio.h:62
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
char * Line() const
Return a pointer to the last line that was read in.
Definition richio.h:98
static NETLIST_READER * GetNetlistReader(NETLIST *aNetlist, const wxString &aNetlistFileName, const wxString &aCompFootprintFileName=wxEmptyString)
Attempt to determine the net list file type of aNetlistFileName and return the appropriate NETLIST_RE...
static NETLIST_FILE_T GuessNetlistFileType(LINE_READER *aLineReader)
Look at aFileHeaderLine to see if it matches any of the netlist file types it knows about.
CMP_READER * m_footprintReader
The reader used to load the footprint links. If NULL, footprint links are not read.
LINE_READER * m_lineReader
The line reader of the netlist.
NETLIST_READER(LINE_READER *aLineReader, NETLIST *aNetlist, CMP_READER *aFootprintLinkReader=nullptr)
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
COMPONENT * GetComponentByReference(const wxString &aReference)
Return a COMPONENT by aReference.
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
wxString From_UTF8(const char *cstring)