KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_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 (C) 1992-2011 Jean-Pierre Charras.
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
26#include <string_utils.h>
27#include <json_common.h>
28
29#include "pcb_netlist.h"
30#include "netlist_reader.h"
32
33using namespace NL_T;
34
35
37{
39
40 parser.Parse();
41
43 {
45
46 // Sort the component pins so they are in the same order as the legacy format. This
47 // is useful for comparing legacy and s-expression netlist dumps.
48 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
49 m_netlist->GetComponent( i )->SortPins();
50 }
51}
52
53
54// KICAD_NETLIST_PARSER
56 NETLIST_LEXER( aReader )
57{
58 m_lineReader = aReader;
59 m_netlist = aNetlist;
60 token = T_NONE;
61}
62
63
65{
66 int curr_level = 0;
67
68 while( ( token = NextTok() ) != T_EOF )
69 {
70 if( token == T_LEFT )
71 curr_level--;
72
73 if( token == T_RIGHT )
74 {
75 curr_level++;
76
77 if( curr_level > 0 )
78 return;
79 }
80 }
81}
82
83
85{
86 int plevel = 0; // the count of ')' to read at end of file after parsing all sections
87
88 while( ( token = NextTok() ) != T_EOF )
89 {
90 if( token == T_LEFT )
91 token = NextTok();
92
93 switch( token )
94 {
95 case T_export: // The netlist starts here.
96 // nothing to do here, just increment the count of ')' to read at end of file
97 plevel++;
98 break;
99
100 case T_version: // The netlist starts here.
101 // version id not yet used: read it but does not use it
102 NextTok();
103 NeedRIGHT();
104 break;
105
106 case T_components: // The section comp starts here.
107 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parse: entering components section" ) );
108 while( ( token = NextTok() ) != T_EOF )
109 {
110 if( token == T_RIGHT )
111 break;
112 else if( token == T_LEFT )
113 token = NextTok();
114
115 if( token == T_comp ) // A component section found. Read it
117 }
118
119 break;
120
121 case T_groups: // The section groups starts here.
122 while( ( token = NextTok() ) != T_EOF )
123 {
124 if( token == T_RIGHT )
125 break;
126 else if( token == T_LEFT )
127 token = NextTok();
128
129 if( token == T_group ) // A group section found. Read it
130 parseGroup();
131 }
132
133 break;
134
135 case T_nets: // The section nets starts here.
136 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parse: entering nets section" ) );
137 while( ( token = NextTok() ) != T_EOF )
138 {
139 if( token == T_RIGHT )
140 break;
141 else if( token == T_LEFT )
142 token = NextTok();
143
144 if( token == T_net ) // A net section if found. Read it
145 parseNet();
146 }
147
148 break;
149
150 case T_libparts: // The section libparts starts here.
151 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parse: entering libparts section" ) );
152 while( ( token = NextTok() ) != T_EOF )
153 {
154 if( token == T_RIGHT )
155 break;
156 else if( token == T_LEFT )
157 token = NextTok();
158
159 if( token == T_libpart ) // A libpart section if found. Read it
161 }
162
163 break;
164
165 case T_libraries: // The section libraries starts here.
166 // List of libraries in use.
167 // Not used here, just skip it
168 skipCurrent();
169 break;
170
171 case T_design: // The section design starts here.
172 // Not used (mainly they are comments), just skip it
173 skipCurrent();
174 break;
175
176 case T_RIGHT: // The closing parenthesis of the file.
177 plevel--;
178 break;
179
180 default:
181 skipCurrent();
182 break;
183 }
184 }
185
186 // Go back and apply group information to the components
187 m_netlist->ApplyGroupMembership();
188
189 if( plevel != 0 )
190 {
191 wxFAIL_MSG( wxString::Format( wxT( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis "
192 "count (count = %d" ),
193 plevel ) );
194 }
195}
196
197
199{
200 /* Parses a section like
201 * (net (code 20) (name /PC-A0)
202 * (node (ref "BUS1") (pin "62)")
203 * (node (ref "U3") ("pin 3") (pin_function "clock"))
204 * (node (ref "U9") (pin "M6") (pin_function "reset")))
205 */
206
207 wxString code;
208 wxString name;
209 wxString reference;
210 wxString pin_number;
211 wxString pin_function;
212 wxString pin_type;
213
214 // The token net was read, so the next data is (code <number>)
215 while( (token = NextTok() ) != T_EOF )
216 {
217 if( token == T_RIGHT )
218 break;
219 else if( token == T_LEFT )
220 token = NextTok();
221
222 switch( token )
223 {
224 case T_code:
225 NeedSYMBOLorNUMBER();
226 code = From_UTF8( CurText() );
227 NeedRIGHT();
228 break;
229
230 case T_name:
231 NeedSYMBOLorNUMBER();
232 name = From_UTF8( CurText() );
233 NeedRIGHT();
234 break;
235
236 case T_node:
237 // By default: no pin function or type.
238 pin_function.Clear();
239 pin_type.Clear();
240
241 while( (token = NextTok() ) != T_EOF )
242 {
243 if( token == T_RIGHT )
244 break;
245 else if( token == T_LEFT )
246 token = NextTok();
247
248 switch( token )
249 {
250 case T_ref:
251 NeedSYMBOLorNUMBER();
252 reference = From_UTF8( CurText() );
253 NeedRIGHT();
254 break;
255
256 case T_pin:
257 NeedSYMBOLorNUMBER();
258 pin_number = From_UTF8( CurText() );
259 NeedRIGHT();
260 break;
261
262 case T_pinfunction:
263 NeedSYMBOLorNUMBER();
264 pin_function = From_UTF8( CurText() );
265 NeedRIGHT();
266 break;
267
268 case T_pintype:
269 NeedSYMBOLorNUMBER();
270 pin_type = From_UTF8( CurText() );
271 NeedRIGHT();
272 break;
273
274 default:
275 skipCurrent();
276 break;
277 }
278 }
279
280 // Don't assume component will be found; it might be "DNP" or "Exclude from board".
281 if( COMPONENT* component = m_netlist->GetComponentByReference( reference ) )
282 {
283 if( strtol( code.c_str(), nullptr, 10 ) >= 1 )
284 {
285 if( name.IsEmpty() ) // Give a dummy net name like N-000009
286 name = wxT("N-00000") + code;
287
288 component->AddNet( pin_number, name, pin_function, pin_type );
289 }
290 }
291
292 break;
293
294 default:
295 skipCurrent();
296 break;
297 }
298 }
299}
300
301
303{
304 /* Parses a section like
305 * (comp (ref P1)
306 * (value DB25FEMALE)
307 * (footprint DB25FC)
308 * (libsource (lib conn) (part DB25))
309 * (property (name PINCOUNT) (value 25))
310 * (sheetpath (names /) (tstamps /))
311 * (component_classes (class (name "CLASS")))
312 * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
313 *
314 * other fields (unused) are skipped
315 * A component need a reference, value, footprint name and a full time stamp
316 * The full time stamp is the sheetpath time stamp + the component time stamp
317 */
318 LIB_ID fpid;
319 wxString footprint;
320 wxString ref;
321 wxString value;
322 wxString library;
323 wxString name;
324 wxString humanSheetPath;
326
327 std::vector<KIID> uuids;
328 std::map<wxString, wxString> properties;
329 nlohmann::ordered_map<wxString, wxString> fields;
330 std::unordered_set<wxString> componentClasses;
331
332 bool duplicatePinsAreJumpers = false;
333 std::vector<std::set<wxString>> jumperPinGroups;
334
335 // The token comp was read, so the next data is (ref P1)
336 while( (token = NextTok() ) != T_RIGHT )
337 {
338 if( token == T_LEFT )
339 token = NextTok();
340
341 switch( token )
342 {
343 case T_ref:
344 NeedSYMBOLorNUMBER();
345 ref = From_UTF8( CurText() );
346 NeedRIGHT();
347 break;
348
349 case T_value:
350 NeedSYMBOLorNUMBER();
351 value = From_UTF8( CurText() );
352 NeedRIGHT();
353 break;
354
355 case T_footprint:
356 NeedSYMBOLorNUMBER();
357 footprint = FromUTF8();
358 NeedRIGHT();
359 break;
360
361 case T_libsource:
362 // Read libsource
363 while( ( token = NextTok() ) != T_RIGHT )
364 {
365 if( token == T_LEFT )
366 token = NextTok();
367
368 if( token == T_lib )
369 {
370 NeedSYMBOLorNUMBER();
371 library = From_UTF8( CurText() );
372 NeedRIGHT();
373 }
374 else if( token == T_part )
375 {
376 NeedSYMBOLorNUMBER();
377 name = From_UTF8( CurText() );
378 NeedRIGHT();
379 }
380 else if( token == T_description )
381 {
382 NeedSYMBOLorNUMBER();
383 NeedRIGHT();
384 }
385 else
386 {
387 Expecting( "part, lib or description" );
388 }
389 }
390 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseComponent: ref='%s' libsource='%s:%s'" ),
391 ref, library, name );
392 break;
393
394 case T_property:
395 {
396 wxString propName;
397 wxString propValue;
398
399 while( (token = NextTok() ) != T_RIGHT )
400 {
401 if( token == T_LEFT )
402 token = NextTok();
403
404 if( token == T_name )
405 {
406 NeedSYMBOLorNUMBER();
407 propName = From_UTF8( CurText() );
408 NeedRIGHT();
409 }
410 else if( token == T_value )
411 {
412 NeedSYMBOLorNUMBER();
413 propValue = From_UTF8( CurText() );
414 NeedRIGHT();
415 }
416 else
417 {
418 Expecting( "name or value" );
419 }
420 }
421
422 if( !propName.IsEmpty() )
423 properties[propName] = std::move( propValue );
424 }
425 break;
426
427 case T_fields:
428 while( ( token = NextTok() ) != T_RIGHT )
429 {
430 if( token == T_LEFT )
431 token = NextTok();
432
433 if( token == T_field )
434 {
435 wxString fieldName;
436 wxString fieldValue;
437
438 while( ( token = NextTok() ) != T_RIGHT )
439 {
440 if( token == T_LEFT )
441 token = NextTok();
442
443 if( token == T_name )
444 {
445 NeedSYMBOLorNUMBER();
446 fieldName = From_UTF8( CurText() );
447 NeedRIGHT();
448 }
449 else if( token == T_STRING )
450 {
451 fieldValue = From_UTF8( CurText() );
452 }
453 }
454
455 if( !fieldName.IsEmpty() )
456 fields[fieldName] = std::move( fieldValue );
457 }
458 else
459 {
460 Expecting( "field" );
461 }
462 }
463 break;
464
465 case T_sheetpath:
466 while( ( token = NextTok() ) != T_EOF )
467 {
468 if( token == T_names )
469 {
470 NeedSYMBOLorNUMBER();
471 humanSheetPath = From_UTF8( CurText() );
472 NeedRIGHT();
473 }
474
475 if( token == T_tstamps )
476 {
477 NeedSYMBOLorNUMBER();
478 path = KIID_PATH( From_UTF8( CurText() ) );
479 NeedRIGHT();
480 break;
481 }
482 }
483
484 NeedRIGHT();
485
486 break;
487
488 case T_tstamps:
489 while( ( token = NextTok() ) != T_EOF )
490 {
491 if( token == T_RIGHT )
492 break;
493
494 uuids.emplace_back( From_UTF8( CurText() ) );
495 }
496
497 break;
498
499 case T_component_classes:
500 while( ( token = NextTok() ) != T_RIGHT )
501 {
502 if( token != T_LEFT )
503 Expecting( T_LEFT );
504
505 if( ( token = NextTok() ) != T_class )
506 Expecting( T_class );
507
508 NeedSYMBOLorNUMBER();
509 componentClasses.insert( From_UTF8( CurText() ) );
510 NeedRIGHT();
511 }
512
513 break;
514
515 case T_duplicate_pin_numbers_are_jumpers:
516 {
517 NeedSYMBOLorNUMBER();
518 duplicatePinsAreJumpers = From_UTF8( CurText() ) == wxT( "1" );
519 NeedRIGHT();
520 break;
521 }
522
523 case T_jumper_pin_groups:
524 {
525 std::set<wxString>* currentGroup = nullptr;
526
527 for( token = NextTok(); currentGroup || token != T_RIGHT; token = NextTok() )
528 {
529 if( token == T_LEFT )
530 token = NextTok();
531
532 switch( token )
533 {
534 case T_group:
535 currentGroup = &jumperPinGroups.emplace_back();
536 break;
537
538 case T_pin:
539 {
540 NeedSYMBOLorNUMBER();
541 wxString padName = From_UTF8( CurText() );
542 NeedRIGHT();
543 wxCHECK2( currentGroup, continue );
544 currentGroup->insert( padName );
545 break;
546 }
547
548 case T_RIGHT:
549 currentGroup = nullptr;
550 break;
551
552 default:
553 Expecting( "group or pin" );
554 }
555 }
556
557 break;
558 }
559
560 default:
561 // Skip not used data (i.e all other tokens)
562 skipCurrent();
563 break;
564 }
565 }
566
567 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
568 {
569 wxString error;
570 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\nofff: %d" ),
571 CurSource(), CurLineNumber(), CurOffset() );
572
573 THROW_IO_ERROR( error );
574 }
575
576 COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
577 component->SetName( name );
578 component->SetLibrary( library );
579 component->SetProperties( properties );
580 component->SetFields( fields );
581 component->SetHumanReadablePath( humanSheetPath );
582 component->SetComponentClassNames( componentClasses );
583 component->SetDuplicatePadNumbersAreJumpers( duplicatePinsAreJumpers );
584 std::ranges::copy( jumperPinGroups, std::inserter( component->JumperPadGroups(),
585 component->JumperPadGroups().end() ) );
586 m_netlist->AddComponent( component );
587}
588
589
591{
592 /* Parses a section like
593 * (groups
594 * (group (name "") (lib_id "DesignBlock:Block") (uuid "7b1488be-4c43-4004-94fc-e4a26dda8f5b")
595 * (members
596 * (member (uuid "dfef752d-e203-4feb-91de-483b44bc4062"))
597 */
598
599 wxString name;
600 KIID uuid;
601 wxString libId; // Design block library link
602 std::vector<KIID> members;
603
604 // The token net was read, so the next data is (code <number>)
605 while( (token = NextTok() ) != T_EOF )
606 {
607 if( token == T_RIGHT )
608 break;
609 else if( token == T_LEFT )
610 token = NextTok();
611
612 switch( token )
613 {
614 case T_name:
615 NeedSYMBOLorNUMBER();
616 name = From_UTF8( CurText() );
617 NeedRIGHT();
618 break;
619
620 case T_uuid:
621 NeedSYMBOLorNUMBER();
622 uuid = From_UTF8( CurText() );
623 NeedRIGHT();
624 break;
625
626 case T_lib_id:
627 NeedSYMBOLorNUMBER();
628 libId = FromUTF8();
629 NeedRIGHT();
630 break;
631
632 case T_members:
633 while( ( token = NextTok() ) != T_RIGHT )
634 {
635 if( token == T_LEFT )
636 token = NextTok();
637
638 if( token == T_member )
639 {
640 wxString memberUuid;
641
642 while( ( token = NextTok() ) != T_RIGHT )
643 {
644 if( token == T_LEFT )
645 token = NextTok();
646
647 if( token == T_uuid )
648 {
649 NeedSYMBOLorNUMBER();
650 memberUuid = From_UTF8( CurText() );
651 NeedRIGHT();
652 }
653 else
654 {
655 Expecting( "uuid" );
656 }
657 }
658
659 members.emplace_back( memberUuid );
660 }
661 else
662 {
663 Expecting( "member" );
664 }
665
666 }
667 break;
668
669 default:
670 skipCurrent();
671 break;
672 }
673 }
674
675 LIB_ID groupLibId;
676
677 if( !libId.IsEmpty() && groupLibId.Parse( libId, true ) >= 0 )
678 {
679 wxString error;
680 error.Printf( _( "Invalid lib_id ID in\nfile: '%s'\nline: %d\nofff: %d" ), CurSource(), CurLineNumber(),
681 CurOffset() );
682
683 THROW_IO_ERROR( error );
684 }
685
686 NETLIST_GROUP* group = new NETLIST_GROUP{ std::move( name ), std::move( uuid ), std::move( groupLibId ),
687 std::move( members ) };
688 m_netlist->AddGroup( group );
689}
690
691
693{
694 /* Parses a section like
695 * (libpart (lib device) (part C)
696 * (aliases
697 * (alias Cxx)
698 * (alias Cyy))
699 * (description "Condensateur non polarise")
700 * (footprints
701 * (fp SM*)
702 * (fp C?)
703 * (fp C1-1))
704 * (fields
705 * (field (name Reference) C)
706 * (field (name Value) C))
707 * (pins
708 * (pin (num 1) (name ~) (type passive))
709 * (pin (num 2) (name ~) (type passive))))
710 *
711 * Currently footprints section/fp are read and data stored
712 * other fields (unused) are skipped
713 */
714 COMPONENT* component = NULL;
715 wxString libName;
716 wxString libPartName;
717 wxArrayString footprintFilters;
718 wxArrayString aliases;
719 int pinCount = 0;
720
721 // The last token read was libpart, so read the next token
722 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: begin libpart" ) );
723 while( (token = NextTok() ) != T_RIGHT )
724 {
725 if( token == T_LEFT )
726 token = NextTok();
727
728 switch( token )
729 {
730 case T_lib:
731 NeedSYMBOLorNUMBER();
732 libName = From_UTF8( CurText() );
733 NeedRIGHT();
734 break;
735
736 case T_part:
737 NeedSYMBOLorNUMBER();
738 libPartName = From_UTF8( CurText() );
739 NeedRIGHT();
740 break;
741
742 case T_footprints:
743 // Read all fp elements (footprint filter item)
744 while( (token = NextTok() ) != T_RIGHT )
745 {
746 if( token == T_LEFT )
747 token = NextTok();
748
749 if( token != T_fp )
750 Expecting( T_fp );
751
752 token = NextTok();
753
754 // Accept an empty (fp) sexpr. We do write them out.
755 if( token == T_RIGHT )
756 continue;
757
758 if( !IsSymbol( token ) && !IsNumber( token ) )
759 Expecting( "footprint ID" );
760
761 footprintFilters.Add( From_UTF8( CurText() ) );
762 NeedRIGHT();
763 }
764 break;
765
766 case T_aliases:
767 while( (token = NextTok() ) != T_RIGHT )
768 {
769 if( token == T_LEFT )
770 token = NextTok();
771
772 if( token != T_alias )
773 Expecting( T_alias );
774
775 NeedSYMBOLorNUMBER();
776 aliases.Add( From_UTF8( CurText() ) );
777 NeedRIGHT();
778 }
779 break;
780
781 case T_pins:
782 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: entering pins for '%s:%s'" ),
783 libName, libPartName );
784 while( (token = NextTok() ) != T_RIGHT )
785 {
786 if( token == T_LEFT )
787 token = NextTok();
788
789 if( token != T_pin )
790 Expecting( T_pin );
791
792 pinCount++;
793 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: pin #%d for '%s:%s'" ),
794 pinCount, libName, libPartName );
795
796 skipCurrent();
797 }
798 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parsed libpart '%s:%s' pins => pinCount=%d" ),
799 libName, libPartName, pinCount );
800 break;
801
802 default:
803 // Skip not used data (i.e all other tokens)
804 skipCurrent();
805 break;
806 }
807 }
808
809 // Find all of the components that reference this component library part definition.
810 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: assigning pinCount=%d for libpart '%s:%s'" ),
811 pinCount, libName, libPartName );
812 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
813 {
814 component = m_netlist->GetComponent( i );
815
816 if( component->IsLibSource( libName, libPartName ) )
817 {
818 component->SetFootprintFilters( footprintFilters );
819 component->SetPinCount( pinCount );
820 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Assign pinCount=%d to component ref='%s' part='%s:%s'" ),
821 pinCount, component->GetReference(), libName, libPartName );
822 }
823
824 for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
825 {
826 if( component->IsLibSource( libName, aliases[jj] ) )
827 {
828 component->SetFootprintFilters( footprintFilters );
829 component->SetPinCount( pinCount );
830 wxLogTrace( "CVPCB_PINCOUNT",
831 wxT( "Assign pinCount=%d to component ref='%s' via alias='%s:%s'" ),
832 pinCount, component->GetReference(), libName, aliases[jj] );
833 }
834 }
835
836 }
837}
const char * name
Store all of the related footprint information found in a netlist.
void SetLibrary(const wxString &aLibrary)
const wxString & GetReference() const
void SetProperties(std::map< wxString, wxString > aProps)
void SetPinCount(int aPinCount)
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
void SetFootprintFilters(const wxArrayString &aFilters)
void SetFields(nlohmann::ordered_map< wxString, wxString > aFields)
void SetHumanReadablePath(const wxString &aPath)
void SetDuplicatePadNumbersAreJumpers(bool aEnabled)
void SetComponentClassNames(const std::unordered_set< wxString > &aClassNames)
std::vector< std::set< wxString > > & JumperPadGroups()
void SetName(const wxString &aName)
The parser for reading the KiCad s-expression netlist format.
KICAD_NETLIST_PARSER(LINE_READER *aReader, NETLIST *aNetlist)
void parseComponent()
Parse a component description: (comp (ref P1) (value DB25FEMELLE) (footprint DB25FC) (libsource (lib ...
void Parse()
Function Parse parse the full netlist.
void parseNet()
Parse a net section (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node (ref U3) (pin 3)) (...
NETLIST * m_netlist
The netlist to parse into. Not owned.
void parseLibPartList()
Read the section "libparts" in the netlist: (libparts (libpart (lib device) (part C) (description "Co...
void parseGroup()
Parse a group section (group (name "GroupName") (member (uuid "..."))))
LINE_READER * m_lineReader
The line reader used to parse the netlist. Not owned.
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
Definition kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:52
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition richio.h:93
NETLIST * m_netlist
The net list to read the file(s) into.
LINE_READER * m_lineReader
The line reader of the netlist.
CMP_READER * m_footprintReader
The reader used to load the footprint links. If NULL, footprint links are not read.
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
static bool IsNumber(char x)
wxString From_UTF8(const char *cstring)