KiCad PCB EDA Suite
sch_legacy_plugin.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) 2016 CERN
5  * Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Wayne Stambaugh <stambaughw@gmail.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <algorithm>
24 #include <boost/algorithm/string/join.hpp>
25 #include <cctype>
26 
27 #include <wx/mstream.h>
28 #include <wx/filename.h>
29 #include <wx/tokenzr.h>
30 #include <pgm_base.h>
31 #include <gr_text.h>
32 #include <kiway.h>
33 #include <kicad_string.h>
34 #include <richio.h>
35 #include <core/typeinfo.h>
36 #include <properties.h>
37 #include <trace_helpers.h>
38 
39 #include <general.h>
40 #include <sch_bitmap.h>
41 #include <sch_bus_entry.h>
42 #include <sch_component.h>
43 #include <sch_junction.h>
44 #include <sch_line.h>
45 #include <sch_marker.h>
46 #include <sch_no_connect.h>
47 #include <sch_text.h>
48 #include <sch_sheet.h>
49 #include <sch_bitmap.h>
50 #include <bus_alias.h>
51 #include <sch_legacy_plugin.h>
52 #include <template_fieldnames.h>
53 #include <sch_screen.h>
54 #include <class_libentry.h>
55 #include <class_library.h>
56 #include <lib_arc.h>
57 #include <lib_bezier.h>
58 #include <lib_circle.h>
59 #include <lib_field.h>
60 #include <lib_pin.h>
61 #include <lib_polyline.h>
62 #include <lib_rectangle.h>
63 #include <lib_text.h>
64 #include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
65 #include <symbol_lib_table.h> // for PropPowerSymsOnly definintion.
66 #include <confirm.h>
67 #include <tool/selection.h>
68 
69 
70 #define Mils2Iu( x ) Mils2iu( x )
71 
72 
73 // Must be the first line of part library document (.dcm) files.
74 #define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
75 
76 #define SCH_PARSE_ERROR( text, reader, pos ) \
77  THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \
78  reader.LineNumber(), pos - reader.Line() )
79 
80 
81 // Token delimiters.
82 const char* delims = " \t\r\n";
83 
84 // Tokens to read/save graphic lines style
85 #define T_STYLE "style"
86 #define T_COLOR "rgb" // cannot be modifed (used by wxWidgets)
87 #define T_COLORA "rgba" // cannot be modifed (used by wxWidgets)
88 #define T_WIDTH "width"
89 
90 
91 static bool is_eol( char c )
92 {
93  // The default file eol character used internally by KiCad.
94  // |
95  // | Possible eol if someone edited the file by hand on certain platforms.
96  // | |
97  // | | May have gone past eol with strtok().
98  // | | |
99  if( c == '\n' || c == '\r' || c == 0 )
100  return true;
101 
102  return false;
103 }
104 
105 
115 static bool strCompare( const char* aString, const char* aLine, const char** aOutput = NULL )
116 {
117  size_t len = strlen( aString );
118  bool retv = ( strncasecmp( aLine, aString, len ) == 0 ) &&
119  ( isspace( aLine[ len ] ) || aLine[ len ] == 0 );
120 
121  if( retv && aOutput )
122  {
123  const char* tmp = aLine;
124 
125  // Move past the end of the token.
126  tmp += len;
127 
128  // Move to the beginning of the next token.
129  while( *tmp && isspace( *tmp ) )
130  tmp++;
131 
132  *aOutput = tmp;
133  }
134 
135  return retv;
136 }
137 
138 
152 static int parseInt( LINE_READER& aReader, const char* aLine, const char** aOutput = NULL )
153 {
154  if( !*aLine )
155  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
156 
157  // Clear errno before calling strtol() in case some other crt call set it.
158  errno = 0;
159 
160  long retv = strtol( aLine, (char**) aOutput, 10 );
161 
162  // Make sure no error occurred when calling strtol().
163  if( errno == ERANGE )
164  SCH_PARSE_ERROR( "invalid integer value", aReader, aLine );
165 
166  // strtol does not strip off whitespace before the next token.
167  if( aOutput )
168  {
169  const char* next = *aOutput;
170 
171  while( *next && isspace( *next ) )
172  next++;
173 
174  *aOutput = next;
175  }
176 
177  return (int) retv;
178 }
179 
180 
194 static uint32_t parseHex( LINE_READER& aReader, const char* aLine,
195  const char** aOutput = NULL )
196 {
197  if( !*aLine )
198  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
199 
200  // Due to some issues between some files created by a 64 bits version and those
201  // created by a 32 bits version, we use here a temporary at least 64 bits storage:
202  unsigned long long retv;
203 
204  // Clear errno before calling strtoull() in case some other crt call set it.
205  errno = 0;
206  retv = strtoull( aLine, (char**) aOutput, 16 );
207 
208  // Make sure no error occurred when calling strtoull().
209  if( errno == ERANGE )
210  SCH_PARSE_ERROR( "invalid hexadecimal number", aReader, aLine );
211 
212  // Strip off whitespace before the next token.
213  if( aOutput )
214  {
215  const char* next = *aOutput;
216 
217  while( *next && isspace( *next ) )
218  next++;
219 
220  *aOutput = next;
221  }
222 
223  return (uint32_t)retv;
224 }
225 
226 
240 static double parseDouble( LINE_READER& aReader, const char* aLine,
241  const char** aOutput = NULL )
242 {
243  if( !*aLine )
244  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
245 
246  // Clear errno before calling strtod() in case some other crt call set it.
247  errno = 0;
248 
249  double retv = strtod( aLine, (char**) aOutput );
250 
251  // Make sure no error occurred when calling strtod().
252  if( errno == ERANGE )
253  SCH_PARSE_ERROR( "invalid floating point number", aReader, aLine );
254 
255  // strtod does not strip off whitespace before the next token.
256  if( aOutput )
257  {
258  const char* next = *aOutput;
259 
260  while( *next && isspace( *next ) )
261  next++;
262 
263  *aOutput = next;
264  }
265 
266  return retv;
267 }
268 
269 
281 static char parseChar( LINE_READER& aReader, const char* aCurrentToken,
282  const char** aNextToken = NULL )
283 {
284  while( *aCurrentToken && isspace( *aCurrentToken ) )
285  aCurrentToken++;
286 
287  if( !*aCurrentToken )
288  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
289 
290  if( !isspace( *( aCurrentToken + 1 ) ) )
291  SCH_PARSE_ERROR( "expected single character token", aReader, aCurrentToken );
292 
293  if( aNextToken )
294  {
295  const char* next = aCurrentToken + 2;
296 
297  while( *next && isspace( *next ) )
298  next++;
299 
300  *aNextToken = next;
301  }
302 
303  return *aCurrentToken;
304 }
305 
306 
321 static void parseUnquotedString( wxString& aString, LINE_READER& aReader,
322  const char* aCurrentToken, const char** aNextToken = NULL,
323  bool aCanBeEmpty = false )
324 {
325  if( !*aCurrentToken )
326  {
327  if( aCanBeEmpty )
328  return;
329  else
330  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
331  }
332 
333  const char* tmp = aCurrentToken;
334 
335  while( *tmp && isspace( *tmp ) )
336  tmp++;
337 
338  if( !*tmp )
339  {
340  if( aCanBeEmpty )
341  return;
342  else
343  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
344  }
345 
346  std::string utf8;
347 
348  while( *tmp && !isspace( *tmp ) )
349  utf8 += *tmp++;
350 
351  aString = FROM_UTF8( utf8.c_str() );
352 
353  if( aString.IsEmpty() && !aCanBeEmpty )
354  SCH_PARSE_ERROR( _( "expected unquoted string" ), aReader, aCurrentToken );
355 
356  if( aNextToken )
357  {
358  const char* next = tmp;
359 
360  while( *next && isspace( *next ) )
361  next++;
362 
363  *aNextToken = next;
364  }
365 }
366 
367 
383 static void parseQuotedString( wxString& aString, LINE_READER& aReader,
384  const char* aCurrentToken, const char** aNextToken = NULL,
385  bool aCanBeEmpty = false )
386 {
387  if( !*aCurrentToken )
388  {
389  if( aCanBeEmpty )
390  return;
391  else
392  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
393  }
394 
395  const char* tmp = aCurrentToken;
396 
397  while( *tmp && isspace( *tmp ) )
398  tmp++;
399 
400  if( !*tmp )
401  {
402  if( aCanBeEmpty )
403  return;
404  else
405  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
406  }
407 
408  // Verify opening quote.
409  if( *tmp != '"' )
410  SCH_PARSE_ERROR( "expecting opening quote", aReader, aCurrentToken );
411 
412  tmp++;
413 
414  std::string utf8; // utf8 without escapes and quotes.
415 
416  // Fetch everything up to closing quote.
417  while( *tmp )
418  {
419  if( *tmp == '\\' )
420  {
421  tmp++;
422 
423  if( !*tmp )
424  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
425 
426  // Do not copy the escape byte if it is followed by \ or "
427  if( *tmp != '"' && *tmp != '\\' )
428  utf8 += '\\';
429 
430  utf8 += *tmp;
431  }
432  else if( *tmp == '"' ) // Closing double quote.
433  {
434  break;
435  }
436  else
437  {
438  utf8 += *tmp;
439  }
440 
441  tmp++;
442  }
443 
444  aString = FROM_UTF8( utf8.c_str() );
445 
446  if( aString.IsEmpty() && !aCanBeEmpty )
447  SCH_PARSE_ERROR( "expected quoted string", aReader, aCurrentToken );
448 
449  if( *tmp && *tmp != '"' )
450  SCH_PARSE_ERROR( "no closing quote for string found", aReader, tmp );
451 
452  // Move past the closing quote.
453  tmp++;
454 
455  if( aNextToken )
456  {
457  const char* next = tmp;
458 
459  while( *next && *next == ' ' )
460  next++;
461 
462  *aNextToken = next;
463  }
464 }
465 
466 
473 {
474  static int m_modHash; // Keep track of the modification status of the library.
475 
476  wxString m_fileName; // Absolute path and file name.
477  wxFileName m_libFileName; // Absolute path and file name is required here.
478  wxDateTime m_fileModTime;
479  LIB_PART_MAP m_symbols; // Map of names of #LIB_PART pointers.
484  int m_libType; // Is this cache a component or symbol library.
485 
486  void loadHeader( FILE_LINE_READER& aReader );
487  static void loadAliases( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader,
488  LIB_PART_MAP* aMap = nullptr );
489  static void loadField( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader );
490  static void loadDrawEntries( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader,
491  int aMajorVersion, int aMinorVersion );
492  static void loadFootprintFilters( std::unique_ptr<LIB_PART>& aPart,
493  LINE_READER& aReader );
494  void loadDocs();
495  static LIB_ARC* loadArc( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader );
496  static LIB_CIRCLE* loadCircle( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader );
497  static LIB_TEXT* loadText( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader,
498  int aMajorVersion, int aMinorVersion );
499  static LIB_RECTANGLE* loadRectangle( std::unique_ptr<LIB_PART>& aPart,
500  LINE_READER& aReader );
501  static LIB_PIN* loadPin( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader );
502  static LIB_POLYLINE* loadPolyLine( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader );
503  static LIB_BEZIER* loadBezier( std::unique_ptr<LIB_PART>& aPart, LINE_READER& aReader );
504 
505  static FILL_T parseFillMode( LINE_READER& aReader, const char* aLine,
506  const char** aOutput );
507  LIB_PART* removeSymbol( LIB_PART* aAlias );
508 
509  void saveDocFile();
510  static void saveArc( LIB_ARC* aArc, OUTPUTFORMATTER& aFormatter );
511  static void saveBezier( LIB_BEZIER* aBezier, OUTPUTFORMATTER& aFormatter );
512  static void saveCircle( LIB_CIRCLE* aCircle, OUTPUTFORMATTER& aFormatter );
513  static void saveField( LIB_FIELD* aField, OUTPUTFORMATTER& aFormatter );
514  static void savePin( LIB_PIN* aPin, OUTPUTFORMATTER& aFormatter );
515  static void savePolyLine( LIB_POLYLINE* aPolyLine, OUTPUTFORMATTER& aFormatter );
516  static void saveRectangle( LIB_RECTANGLE* aRectangle, OUTPUTFORMATTER& aFormatter );
517  static void saveText( LIB_TEXT* aText, OUTPUTFORMATTER& aFormatter );
518 
520 
521 public:
522  SCH_LEGACY_PLUGIN_CACHE( const wxString& aLibraryPath );
524 
525  int GetModifyHash() const { return m_modHash; }
526 
527  // Most all functions in this class throw IO_ERROR exceptions. There are no
528  // error codes nor user interface calls from here, nor in any SCH_PLUGIN objects.
529  // Catch these exceptions higher up please.
530 
532  void Save( bool aSaveDocFile = true );
533 
534  void Load();
535 
536  void AddSymbol( const LIB_PART* aPart );
537 
538  void DeleteSymbol( const wxString& aName );
539 
540  // If m_libFileName is a symlink follow it to the real source file
541  wxFileName GetRealFile() const;
542 
543  wxDateTime GetLibModificationTime();
544 
545  bool IsFile( const wxString& aFullPathAndFileName ) const;
546 
547  bool IsFileChanged() const;
548 
549  void SetModified( bool aModified = true ) { m_isModified = aModified; }
550 
551  wxString GetLogicalName() const { return m_libFileName.GetName(); }
552 
553  void SetFileName( const wxString& aFileName ) { m_libFileName = aFileName; }
554 
555  wxString GetFileName() const { return m_libFileName.GetFullPath(); }
556 
557  static LIB_PART* LoadPart( LINE_READER& aReader, int aMajorVersion, int aMinorVersion,
558  LIB_PART_MAP* aMap = nullptr );
559  static void SaveSymbol( LIB_PART* aSymbol, OUTPUTFORMATTER& aFormatter,
560  LIB_PART_MAP* aMap = nullptr );
561 };
562 
563 
565 {
566  init( NULL );
567 }
568 
569 
571 {
572  delete m_cache;
573 }
574 
575 
576 void SCH_LEGACY_PLUGIN::init( KIWAY* aKiway, const PROPERTIES* aProperties )
577 {
578  m_version = 0;
579  m_rootSheet = NULL;
580  m_props = aProperties;
581  m_kiway = aKiway;
582  m_cache = NULL;
583  m_out = NULL;
584 }
585 
586 
587 SCH_SHEET* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway,
588  SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
589 {
590  wxASSERT( !aFileName || aKiway != NULL );
591 
592  LOCALE_IO toggle; // toggles on, then off, the C locale.
593  SCH_SHEET* sheet;
594 
595  wxFileName fn = aFileName;
596 
597  // Unfortunately child sheet file names the legacy schematic file format are not fully
598  // qualified and are always appended to the project path. The aFileName attribute must
599  // always be an absolute path so the project path can be used for load child sheet files.
600  wxASSERT( fn.IsAbsolute() );
601 
602  if( aAppendToMe )
603  {
604  wxLogTrace( traceSchLegacyPlugin, "Append \"%s\" to sheet \"%s\".",
605  aFileName, aAppendToMe->GetFileName() );
606 
607  wxFileName normedFn = aAppendToMe->GetFileName();
608 
609  if( !normedFn.IsAbsolute() )
610  {
611  if( aFileName.Right( normedFn.GetFullPath().Length() ) == normedFn.GetFullPath() )
612  m_path = aFileName.Left( aFileName.Length() - normedFn.GetFullPath().Length() );
613  }
614 
615  if( m_path.IsEmpty() )
616  m_path = aKiway->Prj().GetProjectPath();
617 
618  wxLogTrace( traceSchLegacyPlugin, "Normalized append path \"%s\".", m_path );
619  }
620  else
621  {
622  m_path = aKiway->Prj().GetProjectPath();
623  }
624 
625  m_currentPath.push( m_path );
626  init( aKiway, aProperties );
627 
628  if( aAppendToMe == NULL )
629  {
630  // Clean up any allocated memory if an exception occurs loading the schematic.
631  std::unique_ptr< SCH_SHEET > newSheet( new SCH_SHEET );
632  newSheet->SetFileName( aFileName );
633  m_rootSheet = newSheet.get();
634  loadHierarchy( newSheet.get() );
635 
636  // If we got here, the schematic loaded successfully.
637  sheet = newSheet.release();
638  }
639  else
640  {
641  m_rootSheet = aAppendToMe->GetRootSheet();
642  wxASSERT( m_rootSheet != NULL );
643  sheet = aAppendToMe;
644  loadHierarchy( sheet );
645  }
646 
647  wxASSERT( m_currentPath.size() == 1 ); // only the project path should remain
648 
649  return sheet;
650 }
651 
652 
653 // Everything below this comment is recursive. Modify with care.
654 
656 {
657  SCH_SCREEN* screen = NULL;
658 
659  if( !aSheet->GetScreen() )
660  {
661  // SCH_SCREEN objects store the full path and file name where the SCH_SHEET object only
662  // stores the file name and extension. Add the project path to the file name and
663  // extension to compare when calling SCH_SHEET::SearchHierarchy().
664  wxFileName fileName = aSheet->GetFileName();
665 
666  if( !fileName.IsAbsolute() )
667  fileName.MakeAbsolute( m_currentPath.top() );
668 
669  // Save the current path so that it gets restored when decending and ascending the
670  // sheet hierarchy which allows for sheet schematic files to be nested in folders
671  // relative to the last path a schematic was loaded from.
672  wxLogTrace( traceSchLegacyPlugin, "Saving path \"%s\"", m_currentPath.top() );
673  m_currentPath.push( fileName.GetPath() );
674  wxLogTrace( traceSchLegacyPlugin, "Current path \"%s\"", m_currentPath.top() );
675  wxLogTrace( traceSchLegacyPlugin, "Loading \"%s\"", fileName.GetFullPath() );
676 
677  m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
678 
679  if( screen )
680  {
681  aSheet->SetScreen( screen );
682 
683  // Do not need to load the sub-sheets - this has already been done.
684  }
685  else
686  {
687  aSheet->SetScreen( new SCH_SCREEN( m_kiway ) );
688  aSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
689 
690  try
691  {
692  loadFile( fileName.GetFullPath(), aSheet->GetScreen() );
693  for( auto aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
694  {
695  assert( aItem->Type() == SCH_SHEET_T );
696  auto sheet = static_cast<SCH_SHEET*>( aItem );
697 
698  // Set the parent to aSheet. This effectively creates a method to find
699  // the root sheet from any sheet so a pointer to the root sheet does not
700  // need to be stored globally. Note: this is not the same as a hierarchy.
701  // Complex hierarchies can have multiple copies of a sheet. This only
702  // provides a simple tree to find the root sheet.
703  sheet->SetParent( aSheet );
704 
705  // Recursion starts here.
706  loadHierarchy( sheet );
707  }
708  }
709  catch( const IO_ERROR& ioe )
710  {
711  // If there is a problem loading the root sheet, there is no recovery.
712  if( aSheet == m_rootSheet )
713  throw( ioe );
714 
715  // For all subsheets, queue up the error message for the caller.
716  if( !m_error.IsEmpty() )
717  m_error += "\n";
718 
719  m_error += ioe.What();
720  }
721  }
722 
723  m_currentPath.pop();
724  wxLogTrace( traceSchLegacyPlugin, "Restoring path \"%s\"", m_currentPath.top() );
725  }
726 }
727 
728 
729 void SCH_LEGACY_PLUGIN::loadFile( const wxString& aFileName, SCH_SCREEN* aScreen )
730 {
731  FILE_LINE_READER reader( aFileName );
732 
733  loadHeader( reader, aScreen );
734 
735  LoadContent( reader, aScreen, m_version );
736 
737  // Unfortunately schematic files prior to version 2 are not terminated with $EndSCHEMATC
738  // so checking for it's existance will fail so just exit here and take our chances. :(
739  if( m_version > 1 )
740  {
741  char* line = reader.Line();
742 
743  while( *line == ' ' )
744  line++;
745 
746  if( !strCompare( "$EndSCHEMATC", line ) )
747  THROW_IO_ERROR( "'$EndSCHEMATC' not found" );
748  }
749 }
750 
751 
752 void SCH_LEGACY_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen, int version )
753 {
754  m_version = version;
755 
756  while( aReader.ReadLine() )
757  {
758  char* line = aReader.Line();
759 
760  while( *line == ' ' )
761  line++;
762 
763  // Either an object will be loaded properly or the file load will fail and raise
764  // an exception.
765  if( strCompare( "$Descr", line ) )
766  loadPageSettings( aReader, aScreen );
767  else if( strCompare( "$Comp", line ) )
768  aScreen->Append( loadComponent( aReader ) );
769  else if( strCompare( "$Sheet", line ) )
770  aScreen->Append( loadSheet( aReader ) );
771  else if( strCompare( "$Bitmap", line ) )
772  aScreen->Append( loadBitmap( aReader ) );
773  else if( strCompare( "Connection", line ) )
774  aScreen->Append( loadJunction( aReader ) );
775  else if( strCompare( "NoConn", line ) )
776  aScreen->Append( loadNoConnect( aReader ) );
777  else if( strCompare( "Wire", line ) )
778  aScreen->Append( loadWire( aReader ) );
779  else if( strCompare( "Entry", line ) )
780  aScreen->Append( loadBusEntry( aReader ) );
781  else if( strCompare( "Text", line ) )
782  aScreen->Append( loadText( aReader ) );
783  else if( strCompare( "BusAlias", line ) )
784  aScreen->AddBusAlias( loadBusAlias( aReader, aScreen ) );
785  else if( strCompare( "$EndSCHEMATC", line ) )
786  return;
787  else
788  SCH_PARSE_ERROR( "unrecognized token", aReader, line );
789  }
790 }
791 
792 
794 {
795  const char* line = aReader.ReadLine();
796 
797  if( !line || !strCompare( "Eeschema Schematic File Version", line, &line ) )
798  {
799  m_error.Printf( _( "\"%s\" does not appear to be an Eeschema file" ),
800  GetChars( aScreen->GetFileName() ) );
802  }
803 
804  // get the file version here.
805  m_version = parseInt( aReader, line, &line );
806 
807  // The next lines are the lib list section, and are mainly comments, like:
808  // LIBS:power
809  // the lib list is not used, but is in schematic file just in case.
810  // It is usually not empty, but we accept empty list.
811  // If empty, there is a legacy section, not used
812  // EELAYER i j
813  // and the last line is
814  // EELAYER END
815  // Skip all lines until the end of header "EELAYER END" is found
816  while( aReader.ReadLine() )
817  {
818  line = aReader.Line();
819 
820  while( *line == ' ' )
821  line++;
822 
823  if( strCompare( "EELAYER END", line ) )
824  return;
825  }
826 
827  THROW_IO_ERROR( _( "Missing 'EELAYER END'" ) );
828 }
829 
830 
832 {
833  wxASSERT( aScreen != NULL );
834 
835  wxString buf;
836  const char* line = aReader.Line();
837 
838  PAGE_INFO pageInfo;
839  TITLE_BLOCK tb;
840 
841  wxCHECK_RET( strCompare( "$Descr", line, &line ), "Invalid sheet description" );
842 
843  parseUnquotedString( buf, aReader, line, &line );
844 
845  if( !pageInfo.SetType( buf ) )
846  SCH_PARSE_ERROR( "invalid page size", aReader, line );
847 
848  int pagew = parseInt( aReader, line, &line );
849  int pageh = parseInt( aReader, line, &line );
850 
851  if( buf == PAGE_INFO::Custom )
852  {
853  pageInfo.SetWidthMils( pagew );
854  pageInfo.SetHeightMils( pageh );
855  }
856  else
857  {
858  wxString orientation;
859 
860  // Non custom size, set portrait if its present. Can be empty string which defaults
861  // to landscape.
862  parseUnquotedString( orientation, aReader, line, &line, true );
863 
864  if( orientation == "portrait" )
865  pageInfo.SetPortrait( true );
866  }
867 
868  aScreen->SetPageSettings( pageInfo );
869 
870  while( line != NULL )
871  {
872  buf.clear();
873 
874  if( !aReader.ReadLine() )
875  SCH_PARSE_ERROR( _( "unexpected end of file" ), aReader, line );
876 
877  line = aReader.Line();
878 
879  if( strCompare( "Sheet", line, &line ) )
880  {
881  aScreen->m_ScreenNumber = parseInt( aReader, line, &line );
882  aScreen->m_NumberOfScreens = parseInt( aReader, line, &line );
883  }
884  else if( strCompare( "Title", line, &line ) )
885  {
886  parseQuotedString( buf, aReader, line, &line, true );
887  tb.SetTitle( buf );
888  }
889  else if( strCompare( "Date", line, &line ) )
890  {
891  parseQuotedString( buf, aReader, line, &line, true );
892  tb.SetDate( buf );
893  }
894  else if( strCompare( "Rev", line, &line ) )
895  {
896  parseQuotedString( buf, aReader, line, &line, true );
897  tb.SetRevision( buf );
898  }
899  else if( strCompare( "Comp", line, &line ) )
900  {
901  parseQuotedString( buf, aReader, line, &line, true );
902  tb.SetCompany( buf );
903  }
904  else if( strCompare( "Comment1", line, &line ) )
905  {
906  parseQuotedString( buf, aReader, line, &line, true );
907  tb.SetComment( 0, buf );
908  }
909  else if( strCompare( "Comment2", line, &line ) )
910  {
911  parseQuotedString( buf, aReader, line, &line, true );
912  tb.SetComment( 1, buf );
913  }
914  else if( strCompare( "Comment3", line, &line ) )
915  {
916  parseQuotedString( buf, aReader, line, &line, true );
917  tb.SetComment( 2, buf );
918  }
919  else if( strCompare( "Comment4", line, &line ) )
920  {
921  parseQuotedString( buf, aReader, line, &line, true );
922  tb.SetComment( 3, buf );
923  }
924  else if( strCompare( "Comment5", line, &line ) )
925  {
926  parseQuotedString( buf, aReader, line, &line, true );
927  tb.SetComment( 4, buf );
928  }
929  else if( strCompare( "Comment6", line, &line ) )
930  {
931  parseQuotedString( buf, aReader, line, &line, true );
932  tb.SetComment( 5, buf );
933  }
934  else if( strCompare( "Comment7", line, &line ) )
935  {
936  parseQuotedString( buf, aReader, line, &line, true );
937  tb.SetComment( 6, buf );
938  }
939  else if( strCompare( "Comment8", line, &line ) )
940  {
941  parseQuotedString( buf, aReader, line, &line, true );
942  tb.SetComment( 7, buf );
943  }
944  else if( strCompare( "Comment9", line, &line ) )
945  {
946  parseQuotedString( buf, aReader, line, &line, true );
947  tb.SetComment( 8, buf );
948  }
949  else if( strCompare( "$EndDescr", line ) )
950  {
951  aScreen->SetTitleBlock( tb );
952  return;
953  }
954  }
955 
956  SCH_PARSE_ERROR( "missing 'EndDescr'", aReader, line );
957 }
958 
959 
961 {
962  std::unique_ptr< SCH_SHEET > sheet( new SCH_SHEET() );
963 
964  sheet->SetTimeStamp( GetNewTimeStamp() );
965 
966  const char* line = aReader.ReadLine();
967 
968  while( line != NULL )
969  {
970  if( strCompare( "S", line, &line ) ) // Sheet dimensions.
971  {
972  wxPoint position;
973 
974  position.x = Mils2Iu( parseInt( aReader, line, &line ) );
975  position.y = Mils2Iu( parseInt( aReader, line, &line ) );
976  sheet->SetPosition( position );
977 
978  wxSize size;
979 
980  size.SetWidth( Mils2Iu( parseInt( aReader, line, &line ) ) );
981  size.SetHeight( Mils2Iu( parseInt( aReader, line, &line ) ) );
982  sheet->SetSize( size );
983  }
984  else if( strCompare( "U", line, &line ) ) // Sheet time stamp.
985  {
986  sheet->SetTimeStamp( parseHex( aReader, line ) );
987  }
988  else if( *line == 'F' ) // Sheet field.
989  {
990  line++;
991 
992  wxString text;
993  int size;
994  int fieldId = parseInt( aReader, line, &line );
995 
996  if( fieldId == 0 || fieldId == 1 ) // Sheet name and file name.
997  {
998  parseQuotedString( text, aReader, line, &line );
999  size = Mils2Iu( parseInt( aReader, line, &line ) );
1000 
1001  if( fieldId == 0 )
1002  {
1003  sheet->SetName( text );
1004  sheet->SetSheetNameSize( size );
1005  }
1006  else
1007  {
1008  sheet->SetFileName( text );
1009  sheet->SetFileNameSize( size );
1010  }
1011  }
1012  else // Sheet pin.
1013  {
1014  // Use a unique_ptr so that we clean up in the case of a throw
1015  std::unique_ptr< SCH_SHEET_PIN > sheetPin( new SCH_SHEET_PIN( sheet.get() ) );
1016 
1017  sheetPin->SetNumber( fieldId );
1018 
1019  // Can be empty fields.
1020  parseQuotedString( text, aReader, line, &line, true );
1021 
1022  sheetPin->SetText( text );
1023 
1024  if( line == NULL )
1025  THROW_IO_ERROR( _( "unexpected end of line" ) );
1026 
1027  switch( parseChar( aReader, line, &line ) )
1028  {
1029  case 'I':
1030  sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_INPUT );
1031  break;
1032 
1033  case 'O':
1034  sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_OUTPUT );
1035  break;
1036 
1037  case 'B':
1038  sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_BIDI );
1039  break;
1040 
1041  case 'T':
1042  sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_TRISTATE );
1043  break;
1044 
1045  case 'U':
1046  sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_UNSPECIFIED );
1047  break;
1048  default:
1049  SCH_PARSE_ERROR( "invalid sheet pin type", aReader, line );
1050  }
1051 
1052  switch( parseChar( aReader, line, &line ) )
1053  {
1054  case 'R': sheetPin->SetEdge( SHEET_RIGHT_SIDE ); break;
1055  case 'T': sheetPin->SetEdge( SHEET_TOP_SIDE ); break;
1056  case 'B': sheetPin->SetEdge( SHEET_BOTTOM_SIDE ); break;
1057  case 'L': sheetPin->SetEdge( SHEET_LEFT_SIDE ); break;
1058  default:
1059  SCH_PARSE_ERROR( "invalid sheet pin side", aReader, line );
1060  }
1061 
1062  wxPoint position;
1063 
1064  position.x = Mils2Iu( parseInt( aReader, line, &line ) );
1065  position.y = Mils2Iu( parseInt( aReader, line, &line ) );
1066  sheetPin->SetPosition( position );
1067 
1068  size = Mils2Iu( parseInt( aReader, line, &line ) );
1069 
1070  sheetPin->SetTextSize( wxSize( size, size ) );
1071 
1072  sheet->AddPin( sheetPin.release() );
1073  }
1074  }
1075  else if( strCompare( "$EndSheet", line ) )
1076  return sheet.release();
1077 
1078  line = aReader.ReadLine();
1079  }
1080 
1081  SCH_PARSE_ERROR( "missing '$EndSheet`", aReader, line );
1082 
1083  return NULL; // Prevents compiler warning. Should never get here.
1084 }
1085 
1086 
1088 {
1089  std::unique_ptr< SCH_BITMAP > bitmap( new SCH_BITMAP );
1090 
1091  const char* line = aReader.Line();
1092 
1093  wxCHECK( strCompare( "$Bitmap", line, &line ), NULL );
1094 
1095  line = aReader.ReadLine();
1096 
1097  while( line != NULL )
1098  {
1099  if( strCompare( "Pos", line, &line ) )
1100  {
1101  wxPoint position;
1102 
1103  position.x = Mils2Iu( parseInt( aReader, line, &line ) );
1104  position.y = Mils2Iu( parseInt( aReader, line, &line ) );
1105  bitmap->SetPosition( position );
1106  }
1107  else if( strCompare( "Scale", line, &line ) )
1108  {
1109  auto scalefactor = parseDouble( aReader, line, &line );
1110 
1111  // Prevent scalefactor values that cannot be displayed.
1112  // In the case of a bad value, we accept that the image might be mis-scaled
1113  // rather than removing the full image. Users can then edit the scale factor in
1114  // Eeschema to the appropriate value
1115  if( !std::isnormal( scalefactor ) )
1116  scalefactor = 1.0;
1117 
1118  bitmap->GetImage()->SetScale( scalefactor );
1119  }
1120  else if( strCompare( "Data", line, &line ) )
1121  {
1122  wxMemoryOutputStream stream;
1123 
1124  while( line )
1125  {
1126  if( !aReader.ReadLine() )
1127  SCH_PARSE_ERROR( _( "Unexpected end of file" ), aReader, line );
1128 
1129  line = aReader.Line();
1130 
1131  if( strCompare( "EndData", line ) )
1132  {
1133  // all the PNG date is read.
1134  // We expect here m_image and m_bitmap are void
1135  wxImage* image = new wxImage();
1136  wxMemoryInputStream istream( stream );
1137  image->LoadFile( istream, wxBITMAP_TYPE_PNG );
1138  bitmap->GetImage()->SetImage( image );
1139  bitmap->GetImage()->SetBitmap( new wxBitmap( *image ) );
1140  break;
1141  }
1142 
1143  // Read PNG data, stored in hexadecimal,
1144  // each byte = 2 hexadecimal digits and a space between 2 bytes
1145  // and put it in memory stream buffer
1146  int len = strlen( line );
1147 
1148  for( ; len > 0 && !isspace( *line ); len -= 3, line += 3 )
1149  {
1150  int value = 0;
1151 
1152  if( sscanf( line, "%X", &value ) == 1 )
1153  stream.PutC( (char) value );
1154  else
1155  THROW_IO_ERROR( "invalid PNG data" );
1156  }
1157  }
1158 
1159  if( line == NULL )
1160  THROW_IO_ERROR( _( "unexpected end of file" ) );
1161  }
1162  else if( strCompare( "$EndBitmap", line ) )
1163  return bitmap.release();
1164 
1165  line = aReader.ReadLine();
1166  }
1167 
1168  THROW_IO_ERROR( _( "unexpected end of file" ) );
1169 }
1170 
1171 
1173 {
1174  std::unique_ptr< SCH_JUNCTION > junction( new SCH_JUNCTION );
1175 
1176  const char* line = aReader.Line();
1177 
1178  wxCHECK( strCompare( "Connection", line, &line ), NULL );
1179 
1180  wxString name;
1181 
1182  parseUnquotedString( name, aReader, line, &line );
1183 
1184  wxPoint position;
1185 
1186  position.x = Mils2Iu( parseInt( aReader, line, &line ) );
1187  position.y = Mils2Iu( parseInt( aReader, line, &line ) );
1188  junction->SetPosition( position );
1189 
1190  return junction.release();
1191 }
1192 
1193 
1195 {
1196  std::unique_ptr< SCH_NO_CONNECT > no_connect( new SCH_NO_CONNECT );
1197 
1198  const char* line = aReader.Line();
1199 
1200  wxCHECK( strCompare( "NoConn", line, &line ), NULL );
1201 
1202  wxString name;
1203 
1204  parseUnquotedString( name, aReader, line, &line );
1205 
1206  wxPoint position;
1207 
1208  position.x = Mils2Iu( parseInt( aReader, line, &line ) );
1209  position.y = Mils2Iu( parseInt( aReader, line, &line ) );
1210  no_connect->SetPosition( position );
1211 
1212  return no_connect.release();
1213 }
1214 
1215 
1217 {
1218  std::unique_ptr< SCH_LINE > wire( new SCH_LINE );
1219 
1220  const char* line = aReader.Line();
1221 
1222  wxCHECK( strCompare( "Wire", line, &line ), NULL );
1223 
1224  if( strCompare( "Wire", line, &line ) )
1225  wire->SetLayer( LAYER_WIRE );
1226  else if( strCompare( "Bus", line, &line ) )
1227  wire->SetLayer( LAYER_BUS );
1228  else if( strCompare( "Notes", line, &line ) )
1229  wire->SetLayer( LAYER_NOTES );
1230  else
1231  SCH_PARSE_ERROR( "invalid line type", aReader, line );
1232 
1233  if( !strCompare( "Line", line, &line ) )
1234  SCH_PARSE_ERROR( "invalid wire definition", aReader, line );
1235 
1236  // Since Sept 15, 2017, a line style is alloved (width, style, color)
1237  // Only non default values are stored
1238  while( !is_eol( *line ) )
1239  {
1240  wxString buf;
1241 
1242  parseUnquotedString( buf, aReader, line, &line );
1243 
1244  if( buf == ")" )
1245  continue;
1246 
1247  else if( buf == T_WIDTH )
1248  {
1249  int size = Mils2Iu( parseInt( aReader, line, &line ) );
1250  wire->SetLineWidth( size );
1251  }
1252  else if( buf == T_STYLE )
1253  {
1254  parseUnquotedString( buf, aReader, line, &line );
1256  wire->SetLineStyle( style );
1257  }
1258  else // should be the color parameter.
1259  {
1260  // The color param is something like rgb(150, 40, 191)
1261  // and because there is no space between ( and 150
1262  // the first param is inside buf.
1263  // So break keyword and the first param into 2 separate strings.
1264  wxString prm, keyword;
1265  keyword = buf.BeforeLast( '(', &prm );
1266 
1267  if( ( keyword == T_COLOR ) || ( keyword == T_COLORA ) )
1268  {
1269  long color[4] = { 0 };
1270 
1271  int ii = 0;
1272 
1273  if( !prm.IsEmpty() )
1274  {
1275  prm.ToLong( &color[ii] );
1276  ii++;
1277  }
1278 
1279  int prm_count = ( keyword == T_COLORA ) ? 4 : 3;
1280  // fix opacity to 1.0 or 255, when not exists in file
1281  color[3] = 255;
1282 
1283  for(; ii < prm_count && !is_eol( *line ); ii++ )
1284  {
1285  color[ii] = parseInt( aReader, line, &line );
1286 
1287  // Skip the separator between values
1288  if( *line == ',' || *line == ' ')
1289  line++;
1290  }
1291 
1292  wire->SetLineColor( color[0]/255.0, color[1]/255.0, color[2]/255.0,color[3]/255.0 );
1293  }
1294  }
1295  }
1296 
1297  // Read the segment en points coordinates:
1298  line = aReader.ReadLine();
1299 
1300  wxPoint begin, end;
1301 
1302  begin.x = Mils2Iu( parseInt( aReader, line, &line ) );
1303  begin.y = Mils2Iu( parseInt( aReader, line, &line ) );
1304  end.x = Mils2Iu( parseInt( aReader, line, &line ) );
1305  end.y = Mils2Iu( parseInt( aReader, line, &line ) );
1306 
1307  wire->SetStartPoint( begin );
1308  wire->SetEndPoint( end );
1309 
1310  return wire.release();
1311 }
1312 
1313 
1315 {
1316  const char* line = aReader.Line();
1317 
1318  wxCHECK( strCompare( "Entry", line, &line ), NULL );
1319 
1320  std::unique_ptr< SCH_BUS_ENTRY_BASE > busEntry;
1321 
1322  if( strCompare( "Wire", line, &line ) )
1323  {
1324  busEntry.reset( new SCH_BUS_WIRE_ENTRY );
1325 
1326  if( !strCompare( "Line", line, &line ) )
1327  SCH_PARSE_ERROR( "invalid bus entry definition expected 'Line'", aReader, line );
1328  }
1329  else if( strCompare( "Bus", line, &line ) )
1330  {
1331  busEntry.reset( new SCH_BUS_BUS_ENTRY );
1332 
1333  if( !strCompare( "Bus", line, &line ) )
1334  SCH_PARSE_ERROR( "invalid bus entry definition expected 'Bus'", aReader, line );
1335  }
1336  else
1337  SCH_PARSE_ERROR( "invalid bus entry type", aReader, line );
1338 
1339  line = aReader.ReadLine();
1340 
1341  wxPoint pos;
1342  wxSize size;
1343 
1344  pos.x = Mils2Iu( parseInt( aReader, line, &line ) );
1345  pos.y = Mils2Iu( parseInt( aReader, line, &line ) );
1346  size.x = Mils2Iu( parseInt( aReader, line, &line ) );
1347  size.y = Mils2Iu( parseInt( aReader, line, &line ) );
1348 
1349  size.x -= pos.x;
1350  size.y -= pos.y;
1351 
1352  busEntry->SetPosition( pos );
1353  busEntry->SetSize( size );
1354 
1355  return busEntry.release();
1356 }
1357 
1358 // clang-format off
1359 const std::map<PINSHEETLABEL_SHAPE, const char*> sheetLabelNames
1361  { PINSHEETLABEL_SHAPE::PS_INPUT, "Input" },
1362  { PINSHEETLABEL_SHAPE::PS_OUTPUT, "Output" },
1363  { PINSHEETLABEL_SHAPE::PS_BIDI, "BiDi" },
1364  { PINSHEETLABEL_SHAPE::PS_TRISTATE, "3State" },
1366 };
1367 // clang-format on
1368 
1369 
1371 {
1372  const char* line = aReader.Line();
1373 
1374  wxCHECK( strCompare( "Text", line, &line ), NULL );
1375 
1376  std::unique_ptr< SCH_TEXT> text;
1377 
1378  if( strCompare( "Notes", line, &line ) )
1379  text.reset( new SCH_TEXT );
1380  else if( strCompare( "Label", line, &line ) )
1381  text.reset( new SCH_LABEL );
1382  else if( strCompare( "HLabel", line, &line ) )
1383  text.reset( new SCH_HIERLABEL );
1384  else if( strCompare( "GLabel", line, &line ) )
1385  {
1386  // Prior to version 2, the SCH_GLOBALLABEL object did not exist.
1387  if( m_version == 1 )
1388  text.reset( new SCH_HIERLABEL );
1389  else
1390  text.reset( new SCH_GLOBALLABEL );
1391  }
1392  else
1393  SCH_PARSE_ERROR( "unknown Text type", aReader, line );
1394 
1395  // Parse the parameters common to all text objects.
1396  wxPoint position;
1397 
1398  position.x = Mils2Iu( parseInt( aReader, line, &line ) );
1399  position.y = Mils2Iu( parseInt( aReader, line, &line ) );
1400  text->SetPosition( position );
1401 
1402  int spinStyle = parseInt( aReader, line, &line );
1403 
1404  // Sadly we store the orientation of hierarchical and global labels using a different
1405  // int encoding than that for local labels:
1406  // Global Local
1407  // Left justified 0 2
1408  // Up 1 3
1409  // Right justified 2 0
1410  // Down 3 1
1411  // So we must flip it as the enum is setup with the "global" numbering
1412  if( text->Type() != SCH_GLOBAL_LABEL_T && text->Type() != SCH_HIER_LABEL_T )
1413  {
1414  if( spinStyle == 0 )
1415  spinStyle = 2;
1416  else if( spinStyle == 2 )
1417  spinStyle = 0;
1418  }
1419 
1420  text->SetLabelSpinStyle( spinStyle );
1421 
1422  int size = Mils2Iu( parseInt( aReader, line, &line ) );
1423 
1424  text->SetTextSize( wxSize( size, size ) );
1425 
1426  // Parse the global and hierarchical label type.
1427  if( text->Type() == SCH_HIER_LABEL_T || text->Type() == SCH_GLOBAL_LABEL_T )
1428  {
1429  auto resultIt = std::find_if( sheetLabelNames.begin(), sheetLabelNames.end(),
1430  [ &line ]( const auto& it )
1431  {
1432  return strCompare( it.second, line, &line );
1433  } );
1434 
1435  if( resultIt != sheetLabelNames.end() )
1436  text->SetShape( resultIt->first );
1437  else
1438  SCH_PARSE_ERROR( "invalid label type", aReader, line );
1439  }
1440 
1441  int thickness = 0;
1442 
1443  // The following tokens do not exist in version 1 schematic files,
1444  // and not always in version 2 for HLabels and GLabels
1445  if( m_version > 1 )
1446  {
1447  if( m_version > 2 || *line >= ' ' )
1448  {
1449  if( strCompare( "Italic", line, &line ) )
1450  text->SetItalic( true );
1451  else if( !strCompare( "~", line, &line ) )
1452  SCH_PARSE_ERROR( _( "expected 'Italics' or '~'" ), aReader, line );
1453  }
1454 
1455  // The thickness token does not exist in older versions of the schematic file format
1456  // so calling parseInt will be made only if the EOL is not reached.
1457  if( *line >= ' ' )
1458  thickness = parseInt( aReader, line, &line );
1459  }
1460 
1461  text->SetBold( thickness != 0 );
1462  text->SetThickness( thickness != 0 ? GetPenSizeForBold( size ) : 0 );
1463 
1464  // Read the text string for the text.
1465  char* tmp = aReader.ReadLine();
1466 
1467  tmp = strtok( tmp, "\r\n" );
1468  wxString val = FROM_UTF8( tmp );
1469 
1470  for( ; ; )
1471  {
1472  int i = val.find( wxT( "\\n" ) );
1473 
1474  if( i == wxNOT_FOUND )
1475  break;
1476 
1477  val.erase( i, 2 );
1478  val.insert( i, wxT( "\n" ) );
1479  }
1480 
1481  text->SetText( val );
1482 
1483  return text.release();
1484 }
1485 
1486 
1488 {
1489  const char* line = aReader.Line();
1490 
1491  wxCHECK( strCompare( "$Comp", line, &line ), NULL );
1492 
1493  std::unique_ptr< SCH_COMPONENT > component( new SCH_COMPONENT() );
1494 
1495  line = aReader.ReadLine();
1496 
1497  while( line != NULL )
1498  {
1499  if( strCompare( "L", line, &line ) )
1500  {
1501  wxString libName;
1502  size_t pos = 2; // "X" plus ' ' space character.
1503  wxString utf8Line = wxString::FromUTF8( line );
1504  wxStringTokenizer tokens( utf8Line, " \r\n\t" );
1505 
1506  if( tokens.CountTokens() < 2 )
1507  THROW_PARSE_ERROR( "invalid symbol library definition", aReader.GetSource(),
1508  aReader.Line(), aReader.LineNumber(), pos );
1509 
1510  libName = tokens.GetNextToken();
1511  libName.Replace( "~", " " );
1512 
1513  LIB_ID libId;
1514 
1515  // Prior to schematic version 4, library IDs did not have a library nickname so
1516  // parsing the symbol name with LIB_ID::Parse() would break symbol library links
1517  // that contained '/' and ':' characters.
1518  if( m_version > 3 )
1519  libId.Parse( libName, LIB_ID::ID_SCH, true );
1520  else
1521  libId.SetLibItemName( libName, false );
1522 
1523  component->SetLibId( libId );
1524 
1525  wxString refDesignator = tokens.GetNextToken();
1526 
1527  refDesignator.Replace( "~", " " );
1528 
1529  wxString prefix = refDesignator;
1530 
1531  while( prefix.Length() )
1532  {
1533  if( ( prefix.Last() < '0' || prefix.Last() > '9') && prefix.Last() != '?' )
1534  break;
1535 
1536  prefix.RemoveLast();
1537  }
1538 
1539  // Avoid a prefix containing trailing/leading spaces
1540  prefix.Trim( true );
1541  prefix.Trim( false );
1542 
1543  if( prefix.IsEmpty() )
1544  component->SetPrefix( wxString( "U" ) );
1545  else
1546  component->SetPrefix( prefix );
1547  }
1548  else if( strCompare( "U", line, &line ) )
1549  {
1550  // This fixes a potentially buggy files caused by unit being set to zero which
1551  // causes netlist issues. See https://bugs.launchpad.net/kicad/+bug/1677282.
1552  int unit = parseInt( aReader, line, &line );
1553 
1554  if( unit == 0 )
1555  {
1556  unit = 1;
1557 
1558  // Set the file as modified so the user can be warned.
1559  if( m_rootSheet && m_rootSheet->GetScreen() )
1561  }
1562 
1563  component->SetUnit( unit );
1564 
1565  // Same can also happen with the convert parameter
1566  int convert = parseInt( aReader, line, &line );
1567 
1568  if( convert == 0 )
1569  {
1570  convert = 1;
1571 
1572  // Set the file as modified so the user can be warned.
1573  if( m_rootSheet && m_rootSheet->GetScreen() )
1575  }
1576 
1577  component->SetConvert( convert );
1578 
1579  component->SetTimeStamp( parseHex( aReader, line, &line ) );
1580  }
1581  else if( strCompare( "P", line, &line ) )
1582  {
1583  wxPoint pos;
1584 
1585  pos.x = Mils2Iu( parseInt( aReader, line, &line ) );
1586  pos.y = Mils2Iu( parseInt( aReader, line, &line ) );
1587  component->SetPosition( pos );
1588  }
1589  else if( strCompare( "AR", line, &line ) )
1590  {
1591  const char* strCompare = "Path=";
1592  int len = strlen( strCompare );
1593 
1594  if( strncasecmp( strCompare, line, len ) != 0 )
1595  SCH_PARSE_ERROR( "missing 'Path=' token", aReader, line );
1596 
1597  line += len;
1598  wxString path, reference, unit;
1599 
1600  parseQuotedString( path, aReader, line, &line );
1601 
1602  strCompare = "Ref=";
1603  len = strlen( strCompare );
1604 
1605  if( strncasecmp( strCompare, line, len ) != 0 )
1606  SCH_PARSE_ERROR( "missing 'Ref=' token", aReader, line );
1607 
1608  line+= len;
1609  parseQuotedString( reference, aReader, line, &line );
1610 
1611  strCompare = "Part=";
1612  len = strlen( strCompare );
1613 
1614  if( strncasecmp( strCompare, line, len ) != 0 )
1615  SCH_PARSE_ERROR( "missing 'Part=' token", aReader, line );
1616 
1617  line+= len;
1618  parseQuotedString( unit, aReader, line, &line );
1619 
1620  long tmp;
1621 
1622  if( !unit.ToLong( &tmp, 10 ) )
1623  SCH_PARSE_ERROR( "expected integer value", aReader, line );
1624 
1625  if( tmp < 0 || tmp > MAX_UNIT_COUNT_PER_PACKAGE )
1626  SCH_PARSE_ERROR( "unit value out of range", aReader, line );
1627 
1628  component->AddHierarchicalReference( path, reference, (int)tmp );
1629  component->GetField( REFERENCE )->SetText( reference );
1630 
1631  }
1632  else if( strCompare( "F", line, &line ) )
1633  {
1634  int index = parseInt( aReader, line, &line );
1635 
1636  wxString text, name;
1637 
1638  parseQuotedString( text, aReader, line, &line, true );
1639 
1640  char orientation = parseChar( aReader, line, &line );
1641  wxPoint pos;
1642  pos.x = Mils2Iu( parseInt( aReader, line, &line ) );
1643  pos.y = Mils2Iu( parseInt( aReader, line, &line ) );
1644  int size = Mils2Iu( parseInt( aReader, line, &line ) );
1645  int attributes = parseHex( aReader, line, &line );
1646 
1647  if( index >= component->GetFieldCount() )
1648  {
1649  // The first MANDATOR_FIELDS _must_ be constructed within
1650  // the SCH_COMPONENT constructor. This assert is simply here
1651  // to guard against a change in that constructor.
1652  wxASSERT( component->GetFieldCount() >= MANDATORY_FIELDS );
1653 
1654  // Ignore the _supplied_ fieldNdx. It is not important anymore
1655  // if within the user defined fields region (i.e. >= MANDATORY_FIELDS).
1656  // We freely renumber the index to fit the next available field slot.
1657  index = component->GetFieldCount(); // new has this index after insertion
1658 
1659  SCH_FIELD field( wxPoint( 0, 0 ), -1, component.get(), name );
1660  component->AddField( field );
1661  }
1662 
1663  // Prior to version 2 of the schematic file format, none of the following existed.
1664  if( m_version > 1 )
1665  {
1666  wxString textAttrs;
1667  char hjustify = parseChar( aReader, line, &line );
1668 
1669  parseUnquotedString( textAttrs, aReader, line, &line );
1670 
1671  // The name of the field is optional.
1672  parseQuotedString( name, aReader, line, &line, true );
1673 
1674  if( hjustify == 'L' )
1675  component->GetField( index )->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
1676  else if( hjustify == 'R' )
1677  component->GetField( index )->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
1678  else if( hjustify != 'C' )
1679  SCH_PARSE_ERROR( "component field text horizontal justification must be "
1680  "L, R, or C", aReader, line );
1681 
1682  // We are guaranteed to have a least one character here for older file formats
1683  // otherwise an exception would have been raised..
1684  if( textAttrs[0] == 'T' )
1685  component->GetField( index )->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
1686  else if( textAttrs[0] == 'B' )
1687  component->GetField( index )->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
1688  else if( textAttrs[0] != 'C' )
1689  SCH_PARSE_ERROR( "component field text vertical justification must be "
1690  "B, T, or C", aReader, line );
1691 
1692  // Newer file formats include the bold and italics text attribute.
1693  if( textAttrs.Length() > 1 )
1694  {
1695  if( textAttrs.Length() != 3 )
1696  SCH_PARSE_ERROR( _( "component field text attributes must be 3 characters wide" ),
1697  aReader, line );
1698 
1699  if( textAttrs[1] == 'I' )
1700  component->GetField( index )->SetItalic( true );
1701  else if( textAttrs[1] != 'N' )
1702  SCH_PARSE_ERROR( "component field text italics indicator must be I or N",
1703  aReader, line );
1704 
1705  if( textAttrs[2] == 'B' )
1706  component->GetField( index )->SetBold( true );
1707  else if( textAttrs[2] != 'N' )
1708  SCH_PARSE_ERROR( "component field text bold indicator must be B or N",
1709  aReader, line );
1710  }
1711  }
1712 
1713  component->GetField( index )->SetText( text );
1714  component->GetField( index )->SetTextPos( pos );
1715  component->GetField( index )->SetVisible( !attributes );
1716  component->GetField( index )->SetTextSize( wxSize( size, size ) );
1717 
1718  if( orientation == 'H' )
1719  component->GetField( index )->SetTextAngle( TEXT_ANGLE_HORIZ );
1720  else if( orientation == 'V' )
1721  component->GetField( index )->SetTextAngle( TEXT_ANGLE_VERT );
1722  else
1723  SCH_PARSE_ERROR( "component field orientation must be H or V",
1724  aReader, line );
1725 
1726  if( name.IsEmpty() )
1728 
1729  component->GetField( index )->SetName( name );
1730  }
1731  else if( strCompare( "$EndComp", line ) )
1732  {
1733  // Ensure all flags (some are set by previous initializations) are reset:
1734  component->ClearFlags();
1735  return component.release();
1736  }
1737  else
1738  {
1739  // There are two lines that begin with a tab or spaces that includes a line with the
1740  // redundant position information and the transform matrix settings.
1741 
1742  // Parse the redundant position information just the same to check for formatting
1743  // errors.
1744  parseInt( aReader, line, &line ); // Always 1.
1745  parseInt( aReader, line, &line ); // The X coordinate.
1746  parseInt( aReader, line, &line ); // The Y coordinate.
1747 
1748  line = aReader.ReadLine();
1749 
1750  TRANSFORM transform;
1751 
1752  transform.x1 = parseInt( aReader, line, &line );
1753 
1754  if( transform.x1 < -1 || transform.x1 > 1 )
1755  SCH_PARSE_ERROR( "invalid component X1 transform value", aReader, line );
1756 
1757  transform.y1 = parseInt( aReader, line, &line );
1758 
1759  if( transform.y1 < -1 || transform.y1 > 1 )
1760  SCH_PARSE_ERROR( "invalid component Y1 transform value", aReader, line );
1761 
1762  transform.x2 = parseInt( aReader, line, &line );
1763 
1764  if( transform.x2 < -1 || transform.x2 > 1 )
1765  SCH_PARSE_ERROR( "invalid component X2 transform value", aReader, line );
1766 
1767  transform.y2 = parseInt( aReader, line, &line );
1768 
1769  if( transform.y2 < -1 || transform.y2 > 1 )
1770  SCH_PARSE_ERROR( "invalid component Y2 transform value", aReader, line );
1771 
1772  component->SetTransform( transform );
1773  }
1774 
1775  line = aReader.ReadLine();
1776  }
1777 
1778  SCH_PARSE_ERROR( "invalid component line", aReader, line );
1779 
1780  return NULL; // Prevents compiler warning. Should never get here.
1781 }
1782 
1783 
1784 std::shared_ptr<BUS_ALIAS> SCH_LEGACY_PLUGIN::loadBusAlias( LINE_READER& aReader,
1785  SCH_SCREEN* aScreen )
1786 {
1787  auto busAlias = std::make_shared< BUS_ALIAS >( aScreen );
1788  const char* line = aReader.Line();
1789 
1790  wxCHECK( strCompare( "BusAlias", line, &line ), NULL );
1791 
1792  wxString buf;
1793  parseUnquotedString( buf, aReader, line, &line );
1794  busAlias->SetName( buf );
1795 
1796  while( *line != '\0' )
1797  {
1798  buf.clear();
1799  parseUnquotedString( buf, aReader, line, &line, true );
1800  if( buf.Len() > 0 )
1801  {
1802  busAlias->AddMember( buf );
1803  }
1804  }
1805 
1806  return busAlias;
1807 }
1808 
1809 
1810 void SCH_LEGACY_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aScreen, KIWAY* aKiway,
1811  const PROPERTIES* aProperties )
1812 {
1813  wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN object." );
1814  wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
1815 
1816  LOCALE_IO toggle; // toggles on, then off, the C locale, to write floating point values.
1817 
1818  init( aKiway, aProperties );
1819 
1820  wxFileName fn = aFileName;
1821 
1822  // File names should be absolute. Don't assume everything relative to the project path
1823  // works properly.
1824  wxASSERT( fn.IsAbsolute() );
1825 
1826  FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
1827 
1828  m_out = &formatter; // no ownership
1829 
1830  Format( aScreen );
1831 }
1832 
1833 
1835 {
1836  wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN* object." );
1837  wxCHECK_RET( m_kiway != NULL, "NULL KIWAY* object." );
1838 
1839  // Write the header
1840  m_out->Print( 0, "%s %s %d\n", "EESchema", SCHEMATIC_HEAD_STRING, EESCHEMA_VERSION );
1841 
1842  // This section is not used, but written for file compatibility
1843  m_out->Print( 0, "EELAYER %d %d\n", SCH_LAYER_ID_COUNT, 0 );
1844  m_out->Print( 0, "EELAYER END\n" );
1845 
1846  /* Write page info, ScreenNumber and NumberOfScreen; not very meaningful for
1847  * SheetNumber and Sheet Count in a complex hierarchy, but useful in
1848  * simple hierarchy and flat hierarchy. Used also to search the root
1849  * sheet ( ScreenNumber = 1 ) within the files
1850  */
1851  const TITLE_BLOCK& tb = aScreen->GetTitleBlock();
1852  const PAGE_INFO& page = aScreen->GetPageSettings();
1853 
1854  m_out->Print( 0, "$Descr %s %d %d%s\n", TO_UTF8( page.GetType() ),
1855  page.GetWidthMils(),
1856  page.GetHeightMils(),
1857  !page.IsCustom() && page.IsPortrait() ? " portrait" : "" );
1858  m_out->Print( 0, "encoding utf-8\n" );
1859  m_out->Print( 0, "Sheet %d %d\n", aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens );
1860  m_out->Print( 0, "Title %s\n", EscapedUTF8( tb.GetTitle() ).c_str() );
1861  m_out->Print( 0, "Date %s\n", EscapedUTF8( tb.GetDate() ).c_str() );
1862  m_out->Print( 0, "Rev %s\n", EscapedUTF8( tb.GetRevision() ).c_str() );
1863  m_out->Print( 0, "Comp %s\n", EscapedUTF8( tb.GetCompany() ).c_str() );
1864  m_out->Print( 0, "Comment1 %s\n", EscapedUTF8( tb.GetComment( 0 ) ).c_str() );
1865  m_out->Print( 0, "Comment2 %s\n", EscapedUTF8( tb.GetComment( 1 ) ).c_str() );
1866  m_out->Print( 0, "Comment3 %s\n", EscapedUTF8( tb.GetComment( 2 ) ).c_str() );
1867  m_out->Print( 0, "Comment4 %s\n", EscapedUTF8( tb.GetComment( 3 ) ).c_str() );
1868  m_out->Print( 0, "Comment5 %s\n", EscapedUTF8( tb.GetComment( 4 ) ).c_str() );
1869  m_out->Print( 0, "Comment6 %s\n", EscapedUTF8( tb.GetComment( 5 ) ).c_str() );
1870  m_out->Print( 0, "Comment7 %s\n", EscapedUTF8( tb.GetComment( 6 ) ).c_str() );
1871  m_out->Print( 0, "Comment8 %s\n", EscapedUTF8( tb.GetComment( 7 ) ).c_str() );
1872  m_out->Print( 0, "Comment9 %s\n", EscapedUTF8( tb.GetComment( 8 ) ).c_str() );
1873  m_out->Print( 0, "$EndDescr\n" );
1874 
1875  for( const auto& alias : aScreen->GetBusAliases() )
1876  {
1877  saveBusAlias( alias );
1878  }
1879 
1880  for( auto item : aScreen->Items() )
1881  {
1882  switch( item->Type() )
1883  {
1884  case SCH_COMPONENT_T:
1885  saveComponent( static_cast<SCH_COMPONENT*>( item ) );
1886  break;
1887  case SCH_BITMAP_T:
1888  saveBitmap( static_cast<SCH_BITMAP*>( item ) );
1889  break;
1890  case SCH_SHEET_T:
1891  saveSheet( static_cast<SCH_SHEET*>( item ) );
1892  break;
1893  case SCH_JUNCTION_T:
1894  saveJunction( static_cast<SCH_JUNCTION*>( item ) );
1895  break;
1896  case SCH_NO_CONNECT_T:
1897  saveNoConnect( static_cast<SCH_NO_CONNECT*>( item ) );
1898  break;
1899  case SCH_BUS_WIRE_ENTRY_T:
1900  case SCH_BUS_BUS_ENTRY_T:
1901  saveBusEntry( static_cast<SCH_BUS_ENTRY_BASE*>( item ) );
1902  break;
1903  case SCH_LINE_T:
1904  saveLine( static_cast<SCH_LINE*>( item ) );
1905  break;
1906  case SCH_TEXT_T:
1907  case SCH_LABEL_T:
1908  case SCH_GLOBAL_LABEL_T:
1909  case SCH_HIER_LABEL_T:
1910  saveText( static_cast<SCH_TEXT*>( item ) );
1911  break;
1912  default:
1913  wxASSERT( "Unexpected schematic object type in SCH_LEGACY_PLUGIN::Format()" );
1914  }
1915  }
1916 
1917  m_out->Print( 0, "$EndSCHEMATC\n" );
1918 }
1919 
1920 
1921 void SCH_LEGACY_PLUGIN::Format( SELECTION* aSelection, OUTPUTFORMATTER* aFormatter )
1922 {
1923  m_out = aFormatter;
1924 
1925  for( unsigned i = 0; i < aSelection->GetSize(); ++i )
1926  {
1927  SCH_ITEM* item = (SCH_ITEM*) aSelection->GetItem( i );
1928 
1929  switch( item->Type() )
1930  {
1931  case SCH_COMPONENT_T:
1932  saveComponent( static_cast< SCH_COMPONENT* >( item ) );
1933  break;
1934  case SCH_BITMAP_T:
1935  saveBitmap( static_cast< SCH_BITMAP* >( item ) );
1936  break;
1937  case SCH_SHEET_T:
1938  saveSheet( static_cast< SCH_SHEET* >( item ) );
1939  break;
1940  case SCH_JUNCTION_T:
1941  saveJunction( static_cast< SCH_JUNCTION* >( item ) );
1942  break;
1943  case SCH_NO_CONNECT_T:
1944  saveNoConnect( static_cast< SCH_NO_CONNECT* >( item ) );
1945  break;
1946  case SCH_BUS_WIRE_ENTRY_T:
1947  case SCH_BUS_BUS_ENTRY_T:
1948  saveBusEntry( static_cast< SCH_BUS_ENTRY_BASE* >( item ) );
1949  break;
1950  case SCH_LINE_T:
1951  saveLine( static_cast< SCH_LINE* >( item ) );
1952  break;
1953  case SCH_TEXT_T:
1954  case SCH_LABEL_T:
1955  case SCH_GLOBAL_LABEL_T:
1956  case SCH_HIER_LABEL_T:
1957  saveText( static_cast< SCH_TEXT* >( item ) );
1958  break;
1959  default:
1960  wxASSERT( "Unexpected schematic object type in SCH_LEGACY_PLUGIN::Format()" );
1961  }
1962  }
1963 }
1964 
1965 
1967 {
1968  std::string name1;
1969  std::string name2;
1970  wxArrayString reference_fields;
1971 
1972  static wxString delimiters( wxT( " " ) );
1973 
1974  // This is redundant with the AR entries below, but it makes the files backwards-compatible.
1975  if( aComponent->GetPathsAndReferences().GetCount() > 0 )
1976  {
1977  reference_fields = wxStringTokenize( aComponent->GetPathsAndReferences()[0], delimiters );
1978  name1 = toUTFTildaText( reference_fields[1] );
1979  }
1980  else
1981  {
1982  if( aComponent->GetField( REFERENCE )->GetText().IsEmpty() )
1983  name1 = toUTFTildaText( aComponent->GetPrefix() );
1984  else
1985  name1 = toUTFTildaText( aComponent->GetField( REFERENCE )->GetText() );
1986  }
1987 
1988  wxString part_name = aComponent->GetLibId().Format();
1989 
1990  if( part_name.size() )
1991  {
1992  name2 = toUTFTildaText( part_name );
1993  }
1994  else
1995  {
1996  name2 = "_NONAME_";
1997  }
1998 
1999  m_out->Print( 0, "$Comp\n" );
2000  m_out->Print( 0, "L %s %s\n", name2.c_str(), name1.c_str() );
2001 
2002  // Generate unit number, convert and time stamp
2003  m_out->Print( 0, "U %d %d %8.8X\n", aComponent->GetUnit(), aComponent->GetConvert(),
2004  aComponent->GetTimeStamp() );
2005 
2006  // Save the position
2007  m_out->Print( 0, "P %d %d\n",
2008  Iu2Mils( aComponent->GetPosition().x ),
2009  Iu2Mils( aComponent->GetPosition().y ) );
2010 
2011  /* If this is a complex hierarchy; save hierarchical references.
2012  * but for simple hierarchies it is not necessary.
2013  * the reference inf is already saved
2014  * this is useful for old Eeschema version compatibility
2015  */
2016  if( aComponent->GetPathsAndReferences().GetCount() > 1 )
2017  {
2018  for( unsigned int ii = 0; ii < aComponent->GetPathsAndReferences().GetCount(); ii++ )
2019  {
2020  /*format:
2021  * AR Path="/140/2" Ref="C99" Part="1"
2022  * where 140 is the uid of the containing sheet
2023  * and 2 is the timestamp of this component.
2024  * (timestamps are actually 8 hex chars)
2025  * Ref is the conventional component reference for this 'path'
2026  * Part is the conventional component part selection for this 'path'
2027  */
2028  reference_fields = wxStringTokenize( aComponent->GetPathsAndReferences()[ii],
2029  delimiters );
2030 
2031  m_out->Print( 0, "AR Path=\"%s\" Ref=\"%s\" Part=\"%s\" \n",
2032  TO_UTF8( reference_fields[0] ),
2033  TO_UTF8( reference_fields[1] ),
2034  TO_UTF8( reference_fields[2] ) );
2035  }
2036  }
2037 
2038  // update the ugly field index, which I would like to see go away someday soon.
2039  for( int i = 0; i < aComponent->GetFieldCount(); ++i )
2040  aComponent->GetField( i )->SetId( i );
2041 
2042  // Fixed fields:
2043  // Save mandatory fields even if they are blank,
2044  // because the visibility, size and orientation are set from library editor.
2045  for( unsigned i = 0; i < MANDATORY_FIELDS; ++i )
2046  saveField( aComponent->GetField( i ) );
2047 
2048  // User defined fields:
2049  // The *policy* about which user defined fields are part of a symbol is now
2050  // only in the dialog editors. No policy should be enforced here, simply
2051  // save all the user defined fields, they are present because a dialog editor
2052  // thought they should be. If you disagree, go fix the dialog editors.
2053  for( int i = MANDATORY_FIELDS; i < aComponent->GetFieldCount(); ++i )
2054  saveField( aComponent->GetField( i ) );
2055 
2056  // Unit number, position, box ( old standard )
2057  m_out->Print( 0, "\t%-4d %-4d %-4d\n", aComponent->GetUnit(),
2058  Iu2Mils( aComponent->GetPosition().x ),
2059  Iu2Mils( aComponent->GetPosition().y ) );
2060 
2061  TRANSFORM transform = aComponent->GetTransform();
2062 
2063  m_out->Print( 0, "\t%-4d %-4d %-4d %-4d\n",
2064  transform.x1, transform.y1, transform.x2, transform.y2 );
2065  m_out->Print( 0, "$EndComp\n" );
2066 }
2067 
2068 
2070 {
2071  char hjustify = 'C';
2072 
2073  if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
2074  hjustify = 'L';
2075  else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
2076  hjustify = 'R';
2077 
2078  char vjustify = 'C';
2079 
2080  if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
2081  vjustify = 'B';
2082  else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
2083  vjustify = 'T';
2084 
2085  m_out->Print( 0, "F %d %s %c %-3d %-3d %-3d %4.4X %c %c%c%c",
2086  aField->GetId(),
2087  EscapedUTF8( aField->GetText() ).c_str(), // wraps in quotes too
2088  aField->GetTextAngle() == TEXT_ANGLE_HORIZ ? 'H' : 'V',
2089  Iu2Mils( aField->GetLibPosition().x ),
2090  Iu2Mils( aField->GetLibPosition().y ),
2091  Iu2Mils( aField->GetTextWidth() ),
2092  !aField->IsVisible(),
2093  hjustify, vjustify,
2094  aField->IsItalic() ? 'I' : 'N',
2095  aField->IsBold() ? 'B' : 'N' );
2096 
2097  // Save field name, if the name is user definable
2098  if( aField->GetId() >= FIELD1 )
2099  {
2100  m_out->Print( 0, " %s", EscapedUTF8( aField->GetName() ).c_str() );
2101  }
2102 
2103  m_out->Print( 0, "\n" );
2104 }
2105 
2106 
2108 {
2109  wxCHECK_RET( aBitmap != NULL, "SCH_BITMAP* is NULL" );
2110 
2111  const wxImage* image = aBitmap->GetImage()->GetImageData();
2112 
2113  wxCHECK_RET( image != NULL, "wxImage* is NULL" );
2114 
2115  m_out->Print( 0, "$Bitmap\n" );
2116  m_out->Print( 0, "Pos %-4d %-4d\n",
2117  Iu2Mils( aBitmap->GetPosition().x ),
2118  Iu2Mils( aBitmap->GetPosition().y ) );
2119  m_out->Print( 0, "Scale %f\n", aBitmap->GetImage()->GetScale() );
2120  m_out->Print( 0, "Data\n" );
2121 
2122  wxMemoryOutputStream stream;
2123 
2124  image->SaveFile( stream, wxBITMAP_TYPE_PNG );
2125 
2126  // Write binary data in hexadecimal form (ASCII)
2127  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
2128  char* begin = (char*) buffer->GetBufferStart();
2129 
2130  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
2131  {
2132  if( ii >= 32 )
2133  {
2134  ii = 0;
2135 
2136  m_out->Print( 0, "\n" );
2137  }
2138 
2139  m_out->Print( 0, "%2.2X ", *begin & 0xFF );
2140  }
2141 
2142  m_out->Print( 0, "\nEndData\n" );
2143  m_out->Print( 0, "$EndBitmap\n" );
2144 }
2145 
2146 
2148 {
2149  wxCHECK_RET( aSheet != NULL, "SCH_SHEET* is NULL" );
2150 
2151  m_out->Print( 0, "$Sheet\n" );
2152  m_out->Print( 0, "S %-4d %-4d %-4d %-4d\n",
2153  Iu2Mils( aSheet->GetPosition().x ), Iu2Mils( aSheet->GetPosition().y ),
2154  Iu2Mils( aSheet->GetSize().x ), Iu2Mils( aSheet->GetSize().y ) );
2155 
2156  m_out->Print( 0, "U %8.8X\n", aSheet->GetTimeStamp() );
2157 
2158  if( !aSheet->GetName().IsEmpty() )
2159  m_out->Print( 0, "F0 %s %d\n", EscapedUTF8( aSheet->GetName() ).c_str(),
2160  Iu2Mils( aSheet->GetSheetNameSize() ) );
2161 
2162  if( !aSheet->GetFileName().IsEmpty() )
2163  m_out->Print( 0, "F1 %s %d\n", EscapedUTF8( aSheet->GetFileName() ).c_str(),
2164  Iu2Mils( aSheet->GetFileNameSize() ) );
2165 
2166  for( const SCH_SHEET_PIN* pin : aSheet->GetPins() )
2167  {
2168  int type, side;
2169 
2170  if( pin->GetText().IsEmpty() )
2171  break;
2172 
2173  switch( pin->GetEdge() )
2174  {
2175  default:
2176  case SHEET_LEFT_SIDE: side = 'L'; break;
2177  case SHEET_RIGHT_SIDE: side = 'R'; break;
2178  case SHEET_TOP_SIDE: side = 'T'; break;
2179  case SHEET_BOTTOM_SIDE: side = 'B'; break;
2180  }
2181 
2182  switch( pin->GetShape() )
2183  {
2185  type = 'I';
2186  break;
2188  type = 'O';
2189  break;
2191  type = 'B';
2192  break;
2194  type = 'T';
2195  break;
2196  default:
2198  type = 'U';
2199  break;
2200  }
2201 
2202  m_out->Print( 0, "F%d %s %c %c %-3d %-3d %-3d\n", pin->GetNumber(),
2203  EscapedUTF8( pin->GetText() ).c_str(), // supplies wrapping quotes
2204  type, side, Iu2Mils( pin->GetPosition().x ),
2205  Iu2Mils( pin->GetPosition().y ),
2206  Iu2Mils( pin->GetTextWidth() ) );
2207  }
2208 
2209  m_out->Print( 0, "$EndSheet\n" );
2210 }
2211 
2212 
2214 {
2215  wxCHECK_RET( aJunction != NULL, "SCH_JUNCTION* is NULL" );
2216 
2217  m_out->Print( 0, "Connection ~ %-4d %-4d\n",
2218  Iu2Mils( aJunction->GetPosition().x ), Iu2Mils( aJunction->GetPosition().y ) );
2219 }
2220 
2221 
2223 {
2224  wxCHECK_RET( aNoConnect != NULL, "SCH_NOCONNECT* is NULL" );
2225 
2226  m_out->Print( 0, "NoConn ~ %-4d %-4d\n", Iu2Mils( aNoConnect->GetPosition().x ),
2227  Iu2Mils( aNoConnect->GetPosition().y ) );
2228 }
2229 
2230 
2232 {
2233  wxCHECK_RET( aBusEntry != NULL, "SCH_BUS_ENTRY_BASE* is NULL" );
2234 
2235  if( aBusEntry->GetLayer() == LAYER_WIRE )
2236  m_out->Print( 0, "Entry Wire Line\n\t%-4d %-4d %-4d %-4d\n",
2237  Iu2Mils( aBusEntry->GetPosition().x ),
2238  Iu2Mils( aBusEntry->GetPosition().y ),
2239  Iu2Mils( aBusEntry->m_End().x ), Iu2Mils( aBusEntry->m_End().y ) );
2240  else
2241  m_out->Print( 0, "Entry Bus Bus\n\t%-4d %-4d %-4d %-4d\n",
2242  Iu2Mils( aBusEntry->GetPosition().x ),
2243  Iu2Mils( aBusEntry->GetPosition().y ),
2244  Iu2Mils( aBusEntry->m_End().x ), Iu2Mils( aBusEntry->m_End().y ) );
2245 }
2246 
2247 
2249 {
2250  wxCHECK_RET( aLine != NULL, "SCH_LINE* is NULL" );
2251 
2252  const char* layer = "Notes";
2253  const char* width = "Line";
2254 
2255  if( aLine->GetLayer() == LAYER_WIRE )
2256  layer = "Wire";
2257  else if( aLine->GetLayer() == LAYER_BUS )
2258  layer = "Bus";
2259 
2260  m_out->Print( 0, "Wire %s %s", layer, width );
2261 
2262  // Write line style (width, type, color) only for non default values
2263  if( aLine->IsGraphicLine() )
2264  {
2265  if( aLine->GetPenSize() != aLine->GetDefaultWidth() )
2266  m_out->Print( 0, " %s %d", T_WIDTH, Iu2Mils( aLine->GetLineSize() ) );
2267 
2268  if( aLine->GetLineStyle() != aLine->GetDefaultStyle() )
2269  m_out->Print( 0, " %s %s", T_STYLE,
2271 
2272  if( aLine->GetLineColor() != aLine->GetDefaultColor() )
2273  m_out->Print( 0, " %s",
2274  TO_UTF8( aLine->GetLineColor().ToColour().GetAsString( wxC2S_CSS_SYNTAX ) ) );
2275  }
2276 
2277  m_out->Print( 0, "\n" );
2278 
2279  m_out->Print( 0, "\t%-4d %-4d %-4d %-4d",
2280  Iu2Mils( aLine->GetStartPoint().x ), Iu2Mils( aLine->GetStartPoint().y ),
2281  Iu2Mils( aLine->GetEndPoint().x ), Iu2Mils( aLine->GetEndPoint().y ) );
2282 
2283  m_out->Print( 0, "\n");
2284 }
2285 
2286 
2288 {
2289  wxCHECK_RET( aText != NULL, "SCH_TEXT* is NULL" );
2290 
2291  const char* italics = "~";
2292  const char* textType = "Notes";
2293 
2294  if( aText->IsItalic() )
2295  italics = "Italic";
2296 
2297  wxString text = aText->GetText();
2298 
2299  SCH_LAYER_ID layer = aText->GetLayer();
2300 
2301  if( layer == LAYER_NOTES || layer == LAYER_LOCLABEL )
2302  {
2303  if( layer == LAYER_NOTES )
2304  {
2305  // For compatibility reasons, the text must be saved in only one text line
2306  // so replace all EOLs with \\n
2307  text.Replace( wxT( "\n" ), wxT( "\\n" ) );
2308 
2309  // Here we should have no CR or LF character in line
2310  // This is not always the case if a multiline text was copied (using a copy/paste
2311  // function) from a text that uses E.O.L characters that differs from the current
2312  // EOL format. This is mainly the case under Linux using LF symbol when copying
2313  // a text from Windows (using CRLF symbol) so we must just remove the extra CR left
2314  // (or LF left under MacOSX)
2315  for( unsigned ii = 0; ii < text.Len(); )
2316  {
2317  if( text[ii] == 0x0A || text[ii] == 0x0D )
2318  text.erase( ii, 1 );
2319  else
2320  ii++;
2321  }
2322  }
2323  else
2324  {
2325  textType = "Label";
2326  }
2327 
2328  // Local labels must have their spin style inverted for left and right
2329  int spinStyle = static_cast<int>( aText->GetLabelSpinStyle() );
2330 
2331  if( spinStyle == 0 )
2332  spinStyle = 2;
2333  else if( spinStyle == 2 )
2334  spinStyle = 0;
2335 
2336  m_out->Print( 0, "Text %s %-4d %-4d %-4d %-4d %s %d\n%s\n", textType,
2337  Iu2Mils( aText->GetPosition().x ), Iu2Mils( aText->GetPosition().y ),
2338  spinStyle,
2339  Iu2Mils( aText->GetTextWidth() ),
2340  italics, Iu2Mils( aText->GetThickness() ), TO_UTF8( text ) );
2341  }
2342  else if( layer == LAYER_GLOBLABEL || layer == LAYER_HIERLABEL )
2343  {
2344  textType = ( layer == LAYER_GLOBLABEL ) ? "GLabel" : "HLabel";
2345 
2346  auto shapeLabelIt = sheetLabelNames.find( aText->GetShape() );
2347  wxCHECK_RET( shapeLabelIt != sheetLabelNames.end(), "Shape not found in names list" );
2348 
2349  m_out->Print( 0, "Text %s %-4d %-4d %-4d %-4d %s %s %d\n%s\n", textType,
2350  Iu2Mils( aText->GetPosition().x ), Iu2Mils( aText->GetPosition().y ),
2351  static_cast<int>( aText->GetLabelSpinStyle() ),
2352  Iu2Mils( aText->GetTextWidth() ),
2353  shapeLabelIt->second,
2354  italics,
2355  Iu2Mils( aText->GetThickness() ), TO_UTF8( text ) );
2356  }
2357 }
2358 
2359 
2360 void SCH_LEGACY_PLUGIN::saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias )
2361 {
2362  wxCHECK_RET( aAlias != NULL, "BUS_ALIAS* is NULL" );
2363 
2364  wxString members = boost::algorithm::join( aAlias->Members(), " " );
2365 
2366  m_out->Print( 0, "BusAlias %s %s\n",
2367  TO_UTF8( aAlias->GetName() ), TO_UTF8( members ) );
2368 }
2369 
2370 
2371 int SCH_LEGACY_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up
2372 
2373 
2374 SCH_LEGACY_PLUGIN_CACHE::SCH_LEGACY_PLUGIN_CACHE( const wxString& aFullPathAndFileName ) :
2375  m_fileName( aFullPathAndFileName ),
2376  m_libFileName( aFullPathAndFileName ),
2377  m_isWritable( true ),
2378  m_isModified( false )
2379 {
2380  m_versionMajor = -1;
2381  m_versionMinor = -1;
2383 }
2384 
2385 
2387 {
2388  std::vector< LIB_PART* > rootParts;
2389 
2390  // When the cache is destroyed, all of the alias objects on the heap should be deleted.
2391  for( LIB_PART_MAP::iterator it = m_symbols.begin(); it != m_symbols.end(); ++it )
2392  delete it->second;
2393 
2394  m_symbols.clear();
2395 }
2396 
2397 
2398 // If m_libFileName is a symlink follow it to the real source file
2400 {
2401  wxFileName fn( m_libFileName );
2402 
2403 #ifndef __WINDOWS__
2404  if( fn.Exists( wxFILE_EXISTS_SYMLINK ) )
2405  {
2406  char buffer[ PATH_MAX + 1 ];
2407  ssize_t pathLen = readlink( TO_UTF8( fn.GetFullPath() ), buffer, PATH_MAX );
2408 
2409  if( pathLen > 0 )
2410  {
2411  buffer[ pathLen ] = '\0';
2412  fn.Assign( fn.GetPath() + wxT( "/" ) + wxString::FromUTF8( buffer ) );
2413  fn.Normalize();
2414  }
2415  }
2416 #endif
2417 
2418  return fn;
2419 }
2420 
2421 
2423 {
2424  wxFileName fn = GetRealFile();
2425 
2426  // update the writable flag while we have a wxFileName, in a network this
2427  // is possibly quite dynamic anyway.
2428  m_isWritable = fn.IsFileWritable();
2429 
2430  return fn.GetModificationTime();
2431 }
2432 
2433 
2434 bool SCH_LEGACY_PLUGIN_CACHE::IsFile( const wxString& aFullPathAndFileName ) const
2435 {
2436  return m_fileName == aFullPathAndFileName;
2437 }
2438 
2439 
2441 {
2442  wxFileName fn = GetRealFile();
2443 
2444  if( m_fileModTime.IsValid() && fn.IsOk() && fn.FileExists() )
2445  return fn.GetModificationTime() != m_fileModTime;
2446 
2447  return false;
2448 }
2449 
2450 
2452 {
2453  wxCHECK_MSG( aPart != NULL, NULL, "NULL pointer cannot be removed from library." );
2454 
2455  LIB_PART* firstChild = NULL;
2456  LIB_PART_MAP::iterator it = m_symbols.find( aPart->GetName() );
2457 
2458  if( it == m_symbols.end() )
2459  return NULL;
2460 
2461  // If the entry pointer doesn't match the name it is mapped to in the library, we
2462  // have done something terribly wrong.
2463  wxCHECK_MSG( *it->second == aPart, NULL,
2464  "Pointer mismatch while attempting to remove alias entry <" + aPart->GetName() +
2465  "> from library cache <" + m_libFileName.GetName() + ">." );
2466 
2467  // If the symbol is a root symbol used by other symbols find the first alias that uses
2468  // the root part and make it the new root.
2469  if( aPart->IsRoot() )
2470  {
2471  for( auto entry : m_symbols )
2472  {
2473  if( entry.second->IsAlias()
2474  && entry.second->GetParent().lock() == aPart->SharedPtr() )
2475  {
2476  firstChild = entry.second;
2477  break;
2478  }
2479  }
2480 
2481  if( firstChild )
2482  {
2483  for( LIB_ITEM& drawItem : aPart->GetDrawItems() )
2484  {
2485  if( drawItem.Type() == LIB_FIELD_T )
2486  {
2487  LIB_FIELD& field = static_cast<LIB_FIELD&>( drawItem );
2488 
2489  if( firstChild->FindField( field.GetName() ) )
2490  continue;
2491  }
2492 
2493  LIB_ITEM* newItem = (LIB_ITEM*) drawItem.Clone();
2494  drawItem.SetParent( firstChild );
2495  firstChild->AddDrawItem( newItem );
2496  }
2497 
2498  // Reparent the remaining aliases.
2499  for( auto entry : m_symbols )
2500  {
2501  if( entry.second->IsAlias()
2502  && entry.second->GetParent().lock() == aPart->SharedPtr() )
2503  entry.second->SetParent( firstChild );
2504  }
2505  }
2506  }
2507 
2508  m_symbols.erase( it );
2509  delete aPart;
2510  m_isModified = true;
2511  ++m_modHash;
2512  return firstChild;
2513 }
2514 
2515 
2517 {
2518  // aPart is cloned in PART_LIB::AddPart(). The cache takes ownership of aPart.
2519  wxString name = aPart->GetName();
2520  LIB_PART_MAP::iterator it = m_symbols.find( name );
2521 
2522  if( it != m_symbols.end() )
2523  {
2524  removeSymbol( it->second );
2525  }
2526 
2527  m_symbols[ name ] = const_cast< LIB_PART* >( aPart );
2528  m_isModified = true;
2529  ++m_modHash;
2530 }
2531 
2532 
2534 {
2535  if( !m_libFileName.FileExists() )
2536  {
2537  THROW_IO_ERROR( wxString::Format( _( "Library file \"%s\" not found." ),
2538  m_libFileName.GetFullPath() ) );
2539  }
2540 
2541  wxCHECK_RET( m_libFileName.IsAbsolute(),
2542  wxString::Format( "Cannot use relative file paths in legacy plugin to "
2543  "open library \"%s\".", m_libFileName.GetFullPath() ) );
2544 
2545  wxLogTrace( traceSchLegacyPlugin, "Loading legacy symbol file \"%s\"",
2546  m_libFileName.GetFullPath() );
2547 
2548  FILE_LINE_READER reader( m_libFileName.GetFullPath() );
2549 
2550  if( !reader.ReadLine() )
2551  THROW_IO_ERROR( _( "unexpected end of file" ) );
2552 
2553  const char* line = reader.Line();
2554 
2555  if( !strCompare( "EESchema-LIBRARY Version", line, &line ) )
2556  {
2557  // Old .sym files (which are libraries with only one symbol, used to store and reuse shapes)
2558  // EESchema-LIB Version x.x SYMBOL. They are valid files.
2559  if( !strCompare( "EESchema-LIB Version", line, &line ) )
2560  SCH_PARSE_ERROR( "file is not a valid component or symbol library file", reader, line );
2561  }
2562 
2563  m_versionMajor = parseInt( reader, line, &line );
2564 
2565  if( *line != '.' )
2566  SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
2567 
2568  line++;
2569 
2570  m_versionMinor = parseInt( reader, line, &line );
2571 
2572  if( m_versionMajor < 1 || m_versionMinor < 0 || m_versionMinor > 99 )
2573  SCH_PARSE_ERROR( "invalid file version in header", reader, line );
2574 
2575  // Check if this is a symbol library which is the same as a component library but without
2576  // any alias, documentation, footprint filters, etc.
2577  if( strCompare( "SYMBOL", line, &line ) )
2578  {
2579  // Symbol files add date and time stamp info to the header.
2581 
2583  }
2584  else
2585  {
2587  }
2588 
2589  while( reader.ReadLine() )
2590  {
2591  line = reader.Line();
2592 
2593  if( *line == '#' || isspace( *line ) ) // Skip comments and blank lines.
2594  continue;
2595 
2596  // Headers where only supported in older library file formats.
2597  if( m_libType == LIBRARY_TYPE_EESCHEMA && strCompare( "$HEADER", line ) )
2598  loadHeader( reader );
2599 
2600  if( strCompare( "DEF", line ) )
2601  {
2602  // Read one DEF/ENDDEF part entry from library:
2604 
2605  m_symbols[ part->GetName() ] = part;
2606  }
2607  }
2608 
2609  ++m_modHash;
2610 
2611  // Remember the file modification time of library file when the
2612  // cache snapshot was made, so that in a networked environment we will
2613  // reload the cache as needed.
2615 
2617  loadDocs();
2618 }
2619 
2620 
2622 {
2623  const char* line;
2624  wxString text;
2625  wxString aliasName;
2626  wxFileName fn = m_libFileName;
2627  LIB_PART* symbol = NULL;;
2628 
2629  fn.SetExt( DOC_EXT );
2630 
2631  // Not all libraries will have a document file.
2632  if( !fn.FileExists() )
2633  return;
2634 
2635  if( !fn.IsFileReadable() )
2636  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to read library "
2637  "document file \"%s\"" ), fn.GetFullPath() ) );
2638 
2639  FILE_LINE_READER reader( fn.GetFullPath() );
2640 
2641  line = reader.ReadLine();
2642 
2643  if( !line )
2644  THROW_IO_ERROR( _( "symbol document library file is empty" ) );
2645 
2646  if( !strCompare( DOCFILE_IDENT, line, &line ) )
2647  SCH_PARSE_ERROR( "invalid document library file version formatting in header",
2648  reader, line );
2649 
2650  while( reader.ReadLine() )
2651  {
2652  line = reader.Line();
2653 
2654  if( *line == '#' ) // Comment line.
2655  continue;
2656 
2657  if( !strCompare( "$CMP", line, &line ) != 0 )
2658  SCH_PARSE_ERROR( "$CMP command expected", reader, line );
2659 
2660  aliasName = wxString::FromUTF8( line );
2661  aliasName.Trim();
2662  aliasName = LIB_ID::FixIllegalChars( aliasName, LIB_ID::ID_SCH );
2663 
2664  LIB_PART_MAP::iterator it = m_symbols.find( aliasName );
2665 
2666  if( it == m_symbols.end() )
2667  wxLogWarning( "Symbol '%s' not found in library:\n\n"
2668  "'%s'\n\nat line %d offset %d", aliasName, fn.GetFullPath(),
2669  reader.LineNumber(), (int) (line - reader.Line() ) );
2670  else
2671  symbol = it->second;
2672 
2673  // Read the curent alias associated doc.
2674  // if the alias does not exist, just skip the description
2675  // (Can happen if a .dcm is not synchronized with the corresponding .lib file)
2676  while( reader.ReadLine() )
2677  {
2678  line = reader.Line();
2679 
2680  if( !line )
2681  SCH_PARSE_ERROR( "unexpected end of file", reader, line );
2682 
2683  if( strCompare( "$ENDCMP", line, &line ) )
2684  break;
2685 
2686  text = FROM_UTF8( line + 2 );
2687  // Remove spaces at eol, and eol chars:
2688  text = text.Trim();
2689 
2690  switch( line[0] )
2691  {
2692  case 'D':
2693  if( symbol )
2694  symbol->SetDescription( text );
2695  break;
2696 
2697  case 'K':
2698  if( symbol )
2699  symbol->SetKeyWords( text );
2700  break;
2701 
2702  case 'F':
2703  if( symbol )
2704  {
2705  symbol->SetDocFileName( text );
2706  symbol->GetField( DATASHEET )->SetText( text );
2707  }
2708  break;
2709 
2710  case 0:
2711  case '\n':
2712  case '\r':
2713  case '#':
2714  // Empty line or commment
2715  break;
2716 
2717  default:
2718  SCH_PARSE_ERROR( "expected token in symbol definition", reader, line );
2719  }
2720  }
2721  }
2722 }
2723 
2724 
2726 {
2727  const char* line = aReader.Line();
2728 
2729  wxASSERT( strCompare( "$HEADER", line, &line ) );
2730 
2731  while( aReader.ReadLine() )
2732  {
2733  line = (char*) aReader;
2734 
2735  // The time stamp saved in old library files is not used or saved in the latest
2736  // library file version.
2737  if( strCompare( "TimeStamp", line, &line ) )
2738  continue;
2739  else if( strCompare( "$ENDHEADER", line, &line ) )
2740  return;
2741  }
2742 
2743  SCH_PARSE_ERROR( "$ENDHEADER not found", aReader, line );
2744 }
2745 
2746 
2748  int aMinorVersion, LIB_PART_MAP* aMap )
2749 {
2750  const char* line = aReader.Line();
2751 
2752  while( *line == '#' )
2753  aReader.ReadLine();
2754 
2755  if( !strCompare( "DEF", line, &line ) )
2756  SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
2757 
2758  long num;
2759  size_t pos = 4; // "DEF" plus the first space.
2760  wxString utf8Line = wxString::FromUTF8( line );
2761  wxStringTokenizer tokens( utf8Line, " \r\n\t" );
2762 
2763  if( tokens.CountTokens() < 8 )
2764  SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
2765 
2766  // Read DEF line:
2767  std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) );
2768 
2769  wxString name, prefix, tmp;
2770 
2771  name = tokens.GetNextToken();
2772  pos += name.size() + 1;
2773 
2774  prefix = tokens.GetNextToken();
2775  pos += prefix.size() + 1;
2776 
2777  tmp = tokens.GetNextToken();
2778  pos += tmp.size() + 1; // NumOfPins, unused.
2779 
2780  tmp = tokens.GetNextToken(); // Pin name offset.
2781 
2782  if( !tmp.ToLong( &num ) )
2783  THROW_PARSE_ERROR( "invalid pin offset", aReader.GetSource(), aReader.Line(),
2784  aReader.LineNumber(), pos );
2785 
2786  pos += tmp.size() + 1;
2787  part->SetPinNameOffset( Mils2Iu( (int)num ) );
2788 
2789  tmp = tokens.GetNextToken(); // Show pin numbers.
2790 
2791  if( !( tmp == "Y" || tmp == "N") )
2792  THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
2793  aReader.LineNumber(), pos );
2794 
2795  pos += tmp.size() + 1;
2796  part->SetShowPinNumbers( ( tmp == "N" ) ? false : true );
2797 
2798  tmp = tokens.GetNextToken(); // Show pin names.
2799 
2800  if( !( tmp == "Y" || tmp == "N") )
2801  THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
2802  aReader.LineNumber(), pos );
2803 
2804  pos += tmp.size() + 1;
2805  part->SetShowPinNames( ( tmp == "N" ) ? false : true );
2806 
2807  tmp = tokens.GetNextToken(); // Number of units.
2808 
2809  if( !tmp.ToLong( &num ) )
2810  THROW_PARSE_ERROR( "invalid unit count", aReader.GetSource(), aReader.Line(),
2811  aReader.LineNumber(), pos );
2812 
2813  pos += tmp.size() + 1;
2814  part->SetUnitCount( (int)num );
2815 
2816  // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
2817  if( part->GetUnitCount() < 1 )
2818  part->SetUnitCount( 1 );
2819 
2820  // Copy part name and prefix.
2821 
2822  // The root alias is added to the alias list by SetName() which is called by SetText().
2823  if( name.IsEmpty() )
2824  {
2825  part->SetName( "~" );
2826  }
2827  else if( name[0] != '~' )
2828  {
2829  part->SetName( name );
2830  }
2831  else
2832  {
2833  part->SetName( name.Right( name.Length() - 1 ) );
2834  part->GetValueField().SetVisible( false );
2835  }
2836 
2837  // Don't set the library alias, this is determined by the symbol library table.
2838  part->SetLibId( LIB_ID( wxEmptyString, part->GetName() ) );
2839 
2840  LIB_FIELD& reference = part->GetReferenceField();
2841 
2842  if( prefix == "~" )
2843  {
2844  reference.Empty();
2845  reference.SetVisible( false );
2846  }
2847  else
2848  {
2849  reference.SetText( prefix );
2850  }
2851 
2852  // In version 2.2 and earlier, this parameter was a '0' which was just a place holder.
2853  // The was no concept of interchangeable multiple unit symbols.
2854  if( LIB_VERSION( aMajorVersion, aMinorVersion ) > 0
2855  && LIB_VERSION( aMajorVersion, aMinorVersion ) <= LIB_VERSION( 2, 2 ) )
2856  {
2857  // Nothing needs to be set since the default setting for symbols with multiple
2858  // units were never interchangeable. Just parse the 0 an move on.
2859  tmp = tokens.GetNextToken();
2860  pos += tmp.size() + 1;
2861  }
2862  else
2863  {
2864  tmp = tokens.GetNextToken();
2865 
2866  if( tmp == "L" )
2867  part->LockUnits( true );
2868  else if( tmp == "F" || tmp == "0" )
2869  part->LockUnits( false );
2870  else
2871  THROW_PARSE_ERROR( "expected L, F, or 0", aReader.GetSource(), aReader.Line(),
2872  aReader.LineNumber(), pos );
2873 
2874  pos += tmp.size() + 1;
2875  }
2876 
2877  // There is the optional power component flag.
2878  if( tokens.HasMoreTokens() )
2879  {
2880  tmp = tokens.GetNextToken();
2881 
2882  if( tmp == "P" )
2883  part->SetPower();
2884  else if( tmp == "N" )
2885  part->SetNormal();
2886  else
2887  THROW_PARSE_ERROR( "expected P or N", aReader.GetSource(), aReader.Line(),
2888  aReader.LineNumber(), pos );
2889  }
2890 
2891  line = aReader.ReadLine();
2892 
2893  // Read lines until "ENDDEF" is found.
2894  while( line )
2895  {
2896  if( *line == '#' ) // Comment
2897  ;
2898  else if( strCompare( "Ti", line, &line ) ) // Modification date is ignored.
2899  continue;
2900  else if( strCompare( "ALIAS", line, &line ) ) // Aliases
2901  loadAliases( part, aReader, aMap );
2902  else if( *line == 'F' ) // Fields
2903  loadField( part, aReader );
2904  else if( strCompare( "DRAW", line, &line ) ) // Drawing objects.
2905  loadDrawEntries( part, aReader, aMajorVersion, aMinorVersion );
2906  else if( strCompare( "$FPLIST", line, &line ) ) // Footprint filter list
2907  loadFootprintFilters( part, aReader );
2908  else if( strCompare( "ENDDEF", line, &line ) ) // End of part description
2909  {
2910  return part.release();
2911  }
2912 
2913  line = aReader.ReadLine();
2914  }
2915 
2916  SCH_PARSE_ERROR( "missing ENDDEF", aReader, line );
2917 }
2918 
2919 
2920 void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr<LIB_PART>& aPart,
2921  LINE_READER& aReader,
2922  LIB_PART_MAP* aMap )
2923 {
2924  wxString newAliasName;
2925  const char* line = aReader.Line();
2926 
2927  wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
2928 
2929  wxString utf8Line = wxString::FromUTF8( line );
2930  wxStringTokenizer tokens( utf8Line, " \r\n\t" );
2931 
2932  // Parse the ALIAS list.
2933  while( tokens.HasMoreTokens() )
2934  {
2935  newAliasName = tokens.GetNextToken();
2936 
2937  if( aMap )
2938  {
2939  LIB_PART* newPart = new LIB_PART( newAliasName );
2940 
2941  newPart->SetParent( aPart.get() );
2942 
2943  // This will prevent duplicate aliases.
2944  (*aMap)[ newPart->GetName() ] = newPart;
2945  }
2946  }
2947 }
2948 
2949 
2950 void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr<LIB_PART>& aPart,
2951  LINE_READER& aReader )
2952 {
2953  const char* line = aReader.Line();
2954 
2955  wxCHECK_RET( *line == 'F', "Invalid field line" );
2956 
2957  wxString text;
2958  int id;
2959 
2960  if( sscanf( line + 1, "%d", &id ) != 1 || id < 0 )
2961  SCH_PARSE_ERROR( "invalid field ID", aReader, line + 1 );
2962 
2963  LIB_FIELD* field;
2964 
2965  if( (unsigned) id < MANDATORY_FIELDS )
2966  {
2967  field = aPart->GetField( id );
2968 
2969  // this will fire only if somebody broke a constructor or editor.
2970  // MANDATORY_FIELDS are always present in ram resident components, no
2971  // exceptions, and they always have their names set, even fixed fields.
2972  wxASSERT( field );
2973  }
2974  else
2975  {
2976  field = new LIB_FIELD( aPart.get(), id );
2977  aPart->AddDrawItem( field );
2978  }
2979 
2980  // Skip to the first double quote.
2981  while( *line != '"' && *line != 0 )
2982  line++;
2983 
2984  if( *line == 0 )
2985  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, line );
2986 
2987  parseQuotedString( text, aReader, line, &line, true );
2988 
2989  field->SetText( text );
2990 
2991  // Doctor the *.lib file field which has a "~" in blank fields. New saves will
2992  // not save like this.
2993  if( text.size() == 1 && text[0] == '~' )
2994  field->SetText( wxEmptyString );
2995  else
2996  field->SetText( text );
2997 
2998  wxPoint pos;
2999 
3000  pos.x = Mils2Iu( parseInt( aReader, line, &line ) );
3001  pos.y = Mils2Iu( parseInt( aReader, line, &line ) );
3002  field->SetPosition( pos );
3003 
3004  wxSize textSize;
3005 
3006  textSize.x = textSize.y = Mils2Iu( parseInt( aReader, line, &line ) );
3007  field->SetTextSize( textSize );
3008 
3009  char textOrient = parseChar( aReader, line, &line );
3010 
3011  if( textOrient == 'H' )
3012  field->SetTextAngle( TEXT_ANGLE_HORIZ );
3013  else if( textOrient == 'V' )
3014  field->SetTextAngle( TEXT_ANGLE_VERT );
3015  else
3016  SCH_PARSE_ERROR( "invalid field text orientation parameter", aReader, line );
3017 
3018  char textVisible = parseChar( aReader, line, &line );
3019 
3020  if( textVisible == 'V' )
3021  field->SetVisible( true );
3022  else if ( textVisible == 'I' )
3023  field->SetVisible( false );
3024  else
3025  SCH_PARSE_ERROR( "invalid field text visibility parameter", aReader, line );
3026 
3027  // It may be technically correct to use the library version to determine if the field text
3028  // attributes are present. If anyone knows if that is valid and what version that would be,
3029  // please change this to test the library version rather than an EOL or the quoted string
3030  // of the field name.
3031  if( *line != 0 && *line != '"' )
3032  {
3033  char textHJustify = parseChar( aReader, line, &line );
3034 
3035  if( textHJustify == 'C' )
3037  else if( textHJustify == 'L' )
3039  else if( textHJustify == 'R' )
3041  else
3042  SCH_PARSE_ERROR( "invalid field text horizontal justification", aReader, line );
3043 
3044  wxString attributes;
3045 
3046  parseUnquotedString( attributes, aReader, line, &line );
3047 
3048  size_t attrSize = attributes.size();
3049 
3050  if( !(attrSize == 3 || attrSize == 1 ) )
3051  SCH_PARSE_ERROR( "invalid field text attributes size", aReader, line );
3052 
3053  switch( (wxChar) attributes[0] )
3054  {
3055  case 'C': field->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
3056  case 'B': field->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
3057  case 'T': field->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
3058  default: SCH_PARSE_ERROR( "invalid field text vertical justification", aReader, line );
3059  }
3060 
3061  if( attrSize == 3 )
3062  {
3063  wxChar attr_1 = attributes[1];
3064  wxChar attr_2 = attributes[2];
3065 
3066  if( attr_1 == 'I' ) // Italic
3067  field->SetItalic( true );
3068  else if( attr_1 != 'N' ) // No italics is default, check for error.
3069  SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
3070 
3071  if ( attr_2 == 'B' ) // Bold
3072  field->SetBold( true );
3073  else if( attr_2 != 'N' ) // No bold is default, check for error.
3074  SCH_PARSE_ERROR( "invalid field text bold parameter", aReader, line );
3075  }
3076  }
3077 
3078  // Fields in RAM must always have names.
3079  if( (unsigned) id < MANDATORY_FIELDS )
3080  {
3081  // Fields in RAM must always have names, because we are trying to get
3082  // less dependent on field ids and more dependent on names.
3083  // Plus assumptions are made in the field editors.
3085 
3086  // Ensure the VALUE field = the part name (can be not the case
3087  // with malformed libraries: edited by hand, or converted from other tools)
3088  if( id == VALUE )
3089  field->SetText( aPart->GetName() );
3090  }
3091  else
3092  {
3093  parseQuotedString( field->m_name, aReader, line, &line, true ); // Optional.
3094  }
3095 }
3096 
3097 
3098 void SCH_LEGACY_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr<LIB_PART>& aPart,
3099  LINE_READER& aReader,
3100  int aMajorVersion,
3101  int aMinorVersion )
3102 {
3103  const char* line = aReader.Line();
3104 
3105  wxCHECK_RET( strCompare( "DRAW", line, &line ), "Invalid DRAW section" );
3106 
3107  line = aReader.ReadLine();
3108 
3109  while( line )
3110  {
3111  if( strCompare( "ENDDRAW", line, &line ) )
3112  return;
3113 
3114  switch( line[0] )
3115  {
3116  case 'A': // Arc
3117  aPart->AddDrawItem( loadArc( aPart, aReader ) );
3118  break;
3119 
3120  case 'C': // Circle
3121  aPart->AddDrawItem( loadCircle( aPart, aReader ) );
3122  break;
3123 
3124  case 'T': // Text
3125  aPart->AddDrawItem( loadText( aPart, aReader, aMajorVersion, aMinorVersion ) );
3126  break;
3127 
3128  case 'S': // Square
3129  aPart->AddDrawItem( loadRectangle( aPart, aReader ) );
3130  break;
3131 
3132  case 'X': // Pin Description
3133  aPart->AddDrawItem( loadPin( aPart, aReader ) );
3134  break;
3135 
3136  case 'P': // Polyline
3137  aPart->AddDrawItem( loadPolyLine( aPart, aReader ) );
3138  break;
3139 
3140  case 'B': // Bezier Curves
3141  aPart->AddDrawItem( loadBezier( aPart, aReader ) );
3142  break;
3143 
3144  case '#': // Comment
3145  case '\n': // Empty line
3146  case '\r':
3147  case 0:
3148  break;
3149 
3150  default:
3151  SCH_PARSE_ERROR( "undefined DRAW entry", aReader, line );
3152  }
3153 
3154  line = aReader.ReadLine();
3155  }
3156 
3157  SCH_PARSE_ERROR( "file ended prematurely loading component draw element", aReader, line );
3158 }
3159 
3160 
3162  const char** aOutput )
3163 {
3164  switch( parseChar( aReader, aLine, aOutput ) )
3165  {
3166  case 'F': return FILLED_SHAPE;
3167  case 'f': return FILLED_WITH_BG_BODYCOLOR;
3168  case 'N': return NO_FILL;
3169  default: SCH_PARSE_ERROR( "invalid fill type, expected f, F, or N", aReader, aLine );
3170  }
3171 }
3172 
3173 
3174 LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_PART>& aPart,
3175  LINE_READER& aReader )
3176 {
3177  const char* line = aReader.Line();
3178 
3179  wxCHECK_MSG( strCompare( "A", line, &line ), NULL, "Invalid LIB_ARC definition" );
3180 
3181  LIB_ARC* arc = new LIB_ARC( aPart.get() );
3182 
3183  wxPoint center;
3184 
3185  center.x = Mils2Iu( parseInt( aReader, line, &line ) );
3186  center.y = Mils2Iu( parseInt( aReader, line, &line ) );
3187 
3188  arc->SetPosition( center );
3189  arc->SetRadius( Mils2Iu( parseInt( aReader, line, &line ) ) );
3190 
3191  int angle1 = parseInt( aReader, line, &line );
3192  int angle2 = parseInt( aReader, line, &line );
3193 
3194  NORMALIZE_ANGLE_POS( angle1 );
3195  NORMALIZE_ANGLE_POS( angle2 );
3196  arc->SetFirstRadiusAngle( angle1 );
3197  arc->SetSecondRadiusAngle( angle2 );
3198 
3199  arc->SetUnit( parseInt( aReader, line, &line ) );
3200  arc->SetConvert( parseInt( aReader, line, &line ) );
3201  arc->SetWidth( Mils2Iu( parseInt( aReader, line, &line ) ) );
3202 
3203  // Old libraries (version <= 2.2) do not have always this FILL MODE param
3204  // when fill mode is no fill (default mode).
3205  if( *line != 0 )
3206  arc->SetFillMode( parseFillMode( aReader, line, &line ) );
3207 
3208  // Actual Coordinates of arc ends are read from file
3209  if( *line != 0 )
3210  {
3211  wxPoint arcStart, arcEnd;
3212 
3213  arcStart.x = Mils2Iu( parseInt( aReader, line, &line ) );
3214  arcStart.y = Mils2Iu( parseInt( aReader, line, &line ) );
3215  arcEnd.x = Mils2Iu( parseInt( aReader, line, &line ) );
3216  arcEnd.y = Mils2Iu( parseInt( aReader, line, &line ) );
3217 
3218  arc->SetStart( arcStart );
3219  arc->SetEnd( arcEnd );
3220  }
3221  else
3222  {
3223  // Actual Coordinates of arc ends are not read from file
3224  // (old library), calculate them
3225  wxPoint arcStart( arc->GetRadius(), 0 );
3226  wxPoint arcEnd( arc->GetRadius(), 0 );
3227 
3228  RotatePoint( &arcStart.x, &arcStart.y, -angle1 );
3229  arcStart += arc->GetPosition();
3230  arc->SetStart( arcStart );
3231  RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 );
3232  arcEnd += arc->GetPosition();
3233  arc->SetEnd( arcEnd );
3234  }
3235 
3236  return arc;
3237 }
3238 
3239 
3240 LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle( std::unique_ptr<LIB_PART>& aPart,
3241  LINE_READER& aReader )
3242 {
3243  const char* line = aReader.Line();
3244 
3245  wxCHECK_MSG( strCompare( "C", line, &line ), NULL, "Invalid LIB_CIRCLE definition" );
3246 
3247  LIB_CIRCLE* circle = new LIB_CIRCLE( aPart.get() );
3248 
3249  wxPoint center;
3250 
3251  center.x = Mils2Iu( parseInt( aReader, line, &line ) );
3252  center.y = Mils2Iu( parseInt( aReader, line, &line ) );
3253 
3254  circle->SetPosition( center );
3255  circle->SetRadius( Mils2Iu( parseInt( aReader, line, &line ) ) );
3256  circle->SetUnit( parseInt( aReader, line, &line ) );
3257  circle->SetConvert( parseInt( aReader, line, &line ) );
3258  circle->SetWidth( Mils2Iu( parseInt( aReader, line, &line ) ) );
3259 
3260  if( *line != 0 )
3261  circle->SetFillMode( parseFillMode( aReader, line, &line ) );
3262 
3263  return circle;
3264 }
3265 
3266 
3267 LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText( std::unique_ptr<LIB_PART>& aPart,
3268  LINE_READER& aReader,
3269  int aMajorVersion,
3270  int aMinorVersion )
3271 {
3272  const char* line = aReader.Line();
3273 
3274  wxCHECK_MSG( strCompare( "T", line, &line ), NULL, "Invalid LIB_TEXT definition" );
3275 
3276  LIB_TEXT* text = new LIB_TEXT( aPart.get() );
3277 
3278  text->SetTextAngle( (double) parseInt( aReader, line, &line ) );
3279 
3280  wxPoint center;
3281 
3282  center.x = Mils2Iu( parseInt( aReader, line, &line ) );
3283  center.y = Mils2Iu( parseInt( aReader, line, &line ) );
3284  text->SetPosition( center );
3285 
3286  wxSize size;
3287 
3288  size.x = size.y = Mils2Iu( parseInt( aReader, line, &line ) );
3289  text->SetTextSize( size );
3290  text->SetVisible( !parseInt( aReader, line, &line ) );
3291  text->SetUnit( parseInt( aReader, line, &line ) );
3292  text->SetConvert( parseInt( aReader, line, &line ) );
3293 
3294  wxString str;
3295 
3296  // If quoted string loading fails, load as not quoted string.
3297  if( *line == '"' )
3298  parseQuotedString( str, aReader, line, &line );
3299  else
3300  {
3301  parseUnquotedString( str, aReader, line, &line );
3302 
3303  // In old libs, "spaces" are replaced by '~' in unquoted strings:
3304  str.Replace( "~", " " );
3305  }
3306 
3307  if( !str.IsEmpty() )
3308  {
3309  // convert two apostrophes back to double quote
3310  str.Replace( "''", "\"" );
3311  }
3312 
3313  text->SetText( str );
3314 
3315  // Here things are murky and not well defined. At some point it appears the format
3316  // was changed to add text properties. However rather than add the token to the end of
3317  // the text definition, it was added after the string and no mention if the file
3318  // verion was bumped or not so this code make break on very old component libraries.
3319  //
3320  // Update: apparently even in the latest version this can be different so added a test
3321  // for end of line before checking for the text properties.
3322  if( LIB_VERSION( aMajorVersion, aMinorVersion ) > 0
3323  && LIB_VERSION( aMajorVersion, aMinorVersion ) > LIB_VERSION( 2, 0 ) && !is_eol( *line ) )
3324  {
3325  if( strCompare( "Italic", line, &line ) )
3326  text->SetItalic( true );
3327  else if( !strCompare( "Normal", line, &line ) )
3328  SCH_PARSE_ERROR( "invalid text stype, expected 'Normal' or 'Italic'", aReader, line );
3329 
3330  if( parseInt( aReader, line, &line ) > 0 )
3331  text->SetBold( true );
3332 
3333  // Some old libaries version > 2.0 do not have these options for text justification:
3334  if( !is_eol( *line ) )
3335  {
3336  switch( parseChar( aReader, line, &line ) )
3337  {
3338  case 'L': text->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); break;
3339  case 'C': text->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER ); break;
3340  case 'R': text->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); break;
3341  default: SCH_PARSE_ERROR( "invalid horizontal text justication; expected L, C, or R",
3342  aReader, line );
3343  }
3344 
3345  switch( parseChar( aReader, line, &line ) )
3346  {
3347  case 'T': text->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
3348  case 'C': text->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
3349  case 'B': text->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
3350  default: SCH_PARSE_ERROR( "invalid vertical text justication; expected T, C, or B",
3351  aReader, line );
3352  }
3353  }
3354  }
3355 
3356  return text;
3357 }
3358 
3359 
3360 LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle( std::unique_ptr<LIB_PART>& aPart,
3361  LINE_READER& aReader )
3362 {
3363  const char* line = aReader.Line();
3364 
3365  wxCHECK_MSG( strCompare( "S", line, &line ), NULL, "Invalid LIB_RECTANGLE definition" );
3366 
3367  LIB_RECTANGLE* rectangle = new LIB_RECTANGLE( aPart.get() );
3368 
3369  wxPoint pos;
3370 
3371  pos.x = Mils2Iu( parseInt( aReader, line, &line ) );
3372  pos.y = Mils2Iu( parseInt( aReader, line, &line ) );
3373  rectangle->SetPosition( pos );
3374 
3375  wxPoint end;
3376 
3377  end.x = Mils2Iu( parseInt( aReader, line, &line ) );
3378  end.y = Mils2Iu( parseInt( aReader, line, &line ) );
3379  rectangle->SetEnd( end );
3380 
3381  rectangle->SetUnit( parseInt( aReader, line, &line ) );
3382  rectangle->SetConvert( parseInt( aReader, line, &line ) );
3383  rectangle->SetWidth( Mils2Iu( parseInt( aReader, line, &line ) ) );
3384 
3385  if( *line != 0 )
3386  rectangle->SetFillMode( parseFillMode( aReader, line, &line ) );
3387 
3388  return rectangle;
3389 }
3390 
3391 
3392 LIB_PIN* SCH_LEGACY_PLUGIN_CACHE::loadPin( std::unique_ptr<LIB_PART>& aPart,
3393  LINE_READER& aReader )
3394 {
3395  const char* line = aReader.Line();
3396 
3397  wxCHECK_MSG( strCompare( "X", line, &line ), NULL, "Invalid LIB_PIN definition" );
3398 
3399  LIB_PIN* pin = new LIB_PIN( aPart.get() );
3400 
3401  size_t pos = 2; // "X" plus ' ' space character.
3402  wxString tmp;
3403  wxString utf8Line = wxString::FromUTF8( line );
3404  wxStringTokenizer tokens( utf8Line, " \r\n\t" );
3405 
3406  if( tokens.CountTokens() < 11 )
3407  SCH_PARSE_ERROR( "invalid pin definition", aReader, line );
3408 
3409  pin->m_name = tokens.GetNextToken();
3410  pos += pin->m_name.size() + 1;
3411  pin->m_number = tokens.GetNextToken();
3412  pos += pin->m_number.size() + 1;
3413 
3414  long num;
3415  wxPoint position;
3416 
3417  tmp = tokens.GetNextToken();
3418 
3419  if( !tmp.ToLong( &num ) )
3420  THROW_PARSE_ERROR( "invalid pin X coordinate", aReader.GetSource(), aReader.Line(),
3421  aReader.LineNumber(), pos );
3422 
3423  pos += tmp.size() + 1;
3424  position.x = Mils2Iu( (int) num );
3425 
3426  tmp = tokens.GetNextToken();
3427 
3428  if( !tmp.ToLong( &num ) )
3429  THROW_PARSE_ERROR( "invalid pin Y coordinate", aReader.GetSource(), aReader.Line(),
3430  aReader.LineNumber(), pos );
3431 
3432  pos += tmp.size() + 1;
3433  position.y = Mils2Iu( (int) num );
3434  pin->m_position = position;
3435 
3436  tmp = tokens.GetNextToken();
3437 
3438  if( !tmp.ToLong( &num ) )
3439  THROW_PARSE_ERROR( "invalid pin length", aReader.GetSource(), aReader.Line(),
3440  aReader.LineNumber(), pos );
3441 
3442  pos += tmp.size() + 1;
3443  pin->m_length = Mils2Iu( (int) num );
3444 
3445 
3446  tmp = tokens.GetNextToken();
3447 
3448  if( tmp.size() > 1 )
3449  THROW_PARSE_ERROR( "invalid pin orientation", aReader.GetSource(), aReader.Line(),
3450  aReader.LineNumber(), pos );
3451 
3452  pos += tmp.size() + 1;
3453  pin->m_orientation = tmp[0];
3454 
3455  tmp = tokens.GetNextToken();
3456 
3457  if( !tmp.ToLong( &num ) )
3458  THROW_PARSE_ERROR( "invalid pin number text size", aReader.GetSource(), aReader.Line(),
3459  aReader.LineNumber(), pos );
3460 
3461  pos += tmp.size() + 1;
3462  pin->m_numTextSize = Mils2Iu( (int) num );
3463 
3464  tmp = tokens.GetNextToken();
3465 
3466  if( !tmp.ToLong( &num ) )
3467  THROW_PARSE_ERROR( "invalid pin name text size", aReader.GetSource(), aReader.Line(),
3468  aReader.LineNumber(), pos );
3469 
3470  pos += tmp.size() + 1;
3471  pin->m_nameTextSize = Mils2Iu( (int) num );
3472 
3473  tmp = tokens.GetNextToken();
3474 
3475  if( !tmp.ToLong( &num ) )
3476  THROW_PARSE_ERROR( "invalid pin unit", aReader.GetSource(), aReader.Line(),
3477  aReader.LineNumber(), pos );
3478 
3479  pos += tmp.size() + 1;
3480  pin->m_Unit = (int) num;
3481 
3482  tmp = tokens.GetNextToken();
3483 
3484  if( !tmp.ToLong( &num ) )
3485  THROW_PARSE_ERROR( "invalid pin alternate body type", aReader.GetSource(), aReader.Line(),
3486  aReader.LineNumber(), pos );
3487 
3488  pos += tmp.size() + 1;
3489  pin->m_Convert = (int) num;
3490 
3491  tmp = tokens.GetNextToken();
3492 
3493  if( tmp.size() != 1 )
3494  THROW_PARSE_ERROR( "invalid pin type", aReader.GetSource(), aReader.Line(),
3495  aReader.LineNumber(), pos );
3496 
3497  pos += tmp.size() + 1;
3498  char type = tmp[0];
3499 
3500  wxString attributes;
3501 
3502  switch( type )
3503  {
3504  case 'I':
3506  break;
3507  case 'O':
3509  break;
3510  case 'B':
3512  break;
3513  case 'T':
3515  break;
3516  case 'P':
3518  break;
3519  case 'U':
3521  break;
3522  case 'W':
3524  break;
3525  case 'w':
3527  break;
3528  case 'C':
3530  break;
3531  case 'E':
3533  break;
3534  case 'N':
3536  break;
3537  default:
3538  THROW_PARSE_ERROR( "unknown pin type", aReader.GetSource(), aReader.Line(),
3539  aReader.LineNumber(), pos );
3540  }
3541 
3542  // Optional
3543  if( tokens.HasMoreTokens() ) /* Special Symbol defined */
3544  {
3545  tmp = tokens.GetNextToken();
3546 
3547  enum
3548  {
3549  INVERTED = 1 << 0,
3550  CLOCK = 1 << 1,
3551  LOWLEVEL_IN = 1 << 2,
3552  LOWLEVEL_OUT = 1 << 3,
3553  FALLING_EDGE = 1 << 4,
3554  NONLOGIC = 1 << 5
3555  };
3556 
3557  int flags = 0;
3558 
3559  for( int j = tmp.size(); j > 0; )
3560  {
3561  switch( tmp[--j].GetValue() )
3562  {
3563  case '~': break;
3564  case 'N': pin->m_attributes |= PIN_INVISIBLE; break;
3565  case 'I': flags |= INVERTED; break;
3566  case 'C': flags |= CLOCK; break;
3567  case 'L': flags |= LOWLEVEL_IN; break;
3568  case 'V': flags |= LOWLEVEL_OUT; break;
3569  case 'F': flags |= FALLING_EDGE; break;
3570  case 'X': flags |= NONLOGIC; break;
3571  default: THROW_PARSE_ERROR( "invalid pin attribut", aReader.GetSource(),
3572  aReader.Line(), aReader.LineNumber(), pos );
3573  }
3574 
3575  pos += 1;
3576  }
3577 
3578  switch( flags )
3579  {
3580  case 0:
3582  break;
3583  case INVERTED:
3585  break;
3586  case CLOCK:
3588  break;
3589  case INVERTED | CLOCK:
3591  break;
3592  case LOWLEVEL_IN:
3594  break;
3595  case LOWLEVEL_IN | CLOCK:
3597  break;
3598  case LOWLEVEL_OUT:
3600  break;
3601  case FALLING_EDGE:
3603  break;
3604  case NONLOGIC:
3606  break;
3607  default:
3608  SCH_PARSE_ERROR( "pin attributes do not define a valid pin shape", aReader, line );
3609  }
3610  }
3611 
3612  return pin;
3613 }
3614 
3615 
3616 LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine( std::unique_ptr<LIB_PART>& aPart,
3617  LINE_READER& aReader )
3618 {
3619  const char* line = aReader.Line();
3620 
3621  wxCHECK_MSG( strCompare( "P", line, &line ), NULL, "Invalid LIB_POLYLINE definition" );
3622 
3623  LIB_POLYLINE* polyLine = new LIB_POLYLINE( aPart.get() );
3624 
3625  int points = parseInt( aReader, line, &line );
3626  polyLine->SetUnit( parseInt( aReader, line, &line ) );
3627  polyLine->SetConvert( parseInt( aReader, line, &line ) );
3628  polyLine->SetWidth( Mils2Iu( parseInt( aReader, line, &line ) ) );
3629  polyLine->Reserve( points );
3630 
3631  wxPoint pt;
3632 
3633  for( int i = 0; i < points; i++ )
3634  {
3635  pt.x = Mils2Iu( parseInt( aReader, line, &line ) );
3636  pt.y = Mils2Iu( parseInt( aReader, line, &line ) );
3637  polyLine->AddPoint( pt );
3638  }
3639 
3640  if( *line != 0 )
3641  polyLine->SetFillMode( parseFillMode( aReader, line, &line ) );
3642 
3643  return polyLine;
3644 }
3645 
3646 
3647 LIB_BEZIER* SCH_LEGACY_PLUGIN_CACHE::loadBezier( std::unique_ptr<LIB_PART>& aPart,
3648  LINE_READER& aReader )
3649 {
3650  const char* line = aReader.Line();
3651 
3652  wxCHECK_MSG( strCompare( "B", line, &line ), NULL, "Invalid LIB_BEZIER definition" );
3653 
3654  LIB_BEZIER* bezier = new LIB_BEZIER( aPart.get() );
3655 
3656  int points = parseInt( aReader, line, &line );
3657  bezier->SetUnit( parseInt( aReader, line, &line ) );
3658  bezier->SetConvert( parseInt( aReader, line, &line ) );
3659  bezier->SetWidth( Mils2Iu( parseInt( aReader, line, &line ) ) );
3660 
3661  wxPoint pt;
3662  bezier->Reserve( points );
3663 
3664  for( int i = 0; i < points; i++ )
3665  {
3666  pt.x = Mils2Iu( parseInt( aReader, line, &line ) );
3667  pt.y = Mils2Iu( parseInt( aReader, line, &line ) );
3668  bezier->AddPoint( pt );
3669  }
3670 
3671  if( *line != 0 )
3672  bezier->SetFillMode( parseFillMode( aReader, line, &line ) );
3673 
3674  return bezier;
3675 }
3676 
3677 
3678 void SCH_LEGACY_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr<LIB_PART>& aPart,
3679  LINE_READER& aReader )
3680 {
3681  const char* line = aReader.Line();
3682 
3683  wxCHECK_RET( strCompare( "$FPLIST", line, &line ), "Invalid footprint filter list" );
3684 
3685  line = aReader.ReadLine();
3686 
3687  wxArrayString footprintFilters;
3688 
3689  while( line )
3690  {
3691  if( strCompare( "$ENDFPLIST", line, &line ) )
3692  {
3693  aPart->SetFootprintFilters( footprintFilters );
3694  return;
3695  }
3696 
3697  wxString footprint;
3698 
3699  parseUnquotedString( footprint, aReader, line, &line );
3700  footprintFilters.Add( footprint );
3701  line = aReader.ReadLine();
3702  }
3703 
3704  SCH_PARSE_ERROR( "file ended prematurely while loading footprint filters", aReader, line );
3705 }
3706 
3707 
3708 void SCH_LEGACY_PLUGIN_CACHE::Save( bool aSaveDocFile )
3709 {
3710  if( !m_isModified )
3711  return;
3712 
3713  // Write through symlinks, don't replace them
3714  wxFileName fn = GetRealFile();
3715 
3716  std::unique_ptr< FILE_OUTPUTFORMATTER > formatter( new FILE_OUTPUTFORMATTER( fn.GetFullPath() ) );
3717  formatter->Print( 0, "%s %d.%d\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
3718  formatter->Print( 0, "#encoding utf-8\n");
3719 
3720  for( LIB_PART_MAP::iterator it = m_symbols.begin(); it != m_symbols.end(); it++ )
3721  {
3722  if( !it->second->IsRoot() )
3723  continue;
3724 
3725  SaveSymbol( it->second, *formatter.get(), &m_symbols );
3726  }
3727 
3728  formatter->Print( 0, "#\n#End Library\n" );
3729  formatter.reset();
3730 
3731  m_fileModTime = fn.GetModificationTime();
3732  m_isModified = false;
3733 
3734  if( aSaveDocFile )
3735  saveDocFile();
3736 }
3737 
3738 
3740  LIB_PART_MAP* aMap )
3741 {
3742  wxCHECK_RET( aSymbol && aSymbol->IsRoot(), "Invalid LIB_PART pointer." );
3743 
3744  // LIB_ALIAS objects are deprecated but we still need to gather up the derived symbols
3745  // and save their names for the old file format.
3746  wxArrayString aliasNames;
3747 
3748  if( aMap )
3749  {
3750  for( auto entry : *aMap )
3751  {
3752  LIB_PART* part = entry.second;
3753 
3754  if( part->IsAlias() && part->GetParent().lock() == aSymbol->SharedPtr() )
3755  aliasNames.Add( part->GetName() );
3756  }
3757  }
3758 
3759  LIB_FIELD& value = aSymbol->GetValueField();
3760 
3761  // First line: it s a comment (component name for readers)
3762  aFormatter.Print( 0, "#\n# %s\n#\n", TO_UTF8( value.GetText() ) );
3763 
3764  // Save data
3765  aFormatter.Print( 0, "DEF" );
3766  aFormatter.Print( 0, " %s", TO_UTF8( value.GetText() ) );
3767 
3768  LIB_FIELD& reference = aSymbol->GetReferenceField();
3769 
3770  if( !reference.GetText().IsEmpty() )
3771  {
3772  aFormatter.Print( 0, " %s", TO_UTF8( reference.GetText() ) );
3773  }
3774  else
3775  {
3776  aFormatter.Print( 0, " ~" );
3777  }
3778 
3779  aFormatter.Print( 0, " %d %d %c %c %d %c %c\n",
3780  0, Iu2Mils( aSymbol->GetPinNameOffset() ),
3781  aSymbol->ShowPinNumbers() ? 'Y' : 'N',
3782  aSymbol->ShowPinNames() ? 'Y' : 'N',
3783  aSymbol->GetUnitCount(), aSymbol->UnitsLocked() ? 'L' : 'F',
3784  aSymbol->IsPower() ? 'P' : 'N' );
3785 
3786  timestamp_t dateModified = aSymbol->GetDateLastEdition();
3787 
3788  if( dateModified != 0 )
3789  {
3790  int sec = dateModified & 63;
3791  int min = ( dateModified >> 6 ) & 63;
3792  int hour = ( dateModified >> 12 ) & 31;
3793  int day = ( dateModified >> 17 ) & 31;
3794  int mon = ( dateModified >> 22 ) & 15;
3795  int year = ( dateModified >> 26 ) + 1990;
3796 
3797  aFormatter.Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec );
3798  }
3799 
3800  LIB_FIELDS fields;
3801  aSymbol->GetFields( fields );
3802 
3803  // Mandatory fields:
3804  // may have their own save policy so there is a separate loop for them.
3805  // Empty fields are saved, because the user may have set visibility,
3806  // size and orientation
3807  for( int i = 0; i < MANDATORY_FIELDS; ++i )
3808  {
3809  saveField( &fields[i], aFormatter );
3810  }
3811 
3812  // User defined fields:
3813  // may have their own save policy so there is a separate loop for them.
3814 
3815  int fieldId = MANDATORY_FIELDS; // really wish this would go away.
3816 
3817  for( unsigned i = MANDATORY_FIELDS; i < fields.size(); ++i )
3818  {
3819  // There is no need to save empty fields, i.e. no reason to preserve field
3820  // names now that fields names come in dynamically through the template
3821  // fieldnames.
3822  if( !fields[i].GetText().IsEmpty() )
3823  {
3824  fields[i].SetId( fieldId++ );
3825  saveField( &fields[i], aFormatter );
3826  }
3827  }
3828 
3829  // Save the alias list: a line starting by "ALIAS".
3830  if( !aliasNames.IsEmpty() )
3831  {
3832  aFormatter.Print( 0, "ALIAS" );
3833 
3834  for( unsigned i = 0; i < aliasNames.GetCount(); i++ )
3835  {
3836  aFormatter.Print( 0, " %s", TO_UTF8( aliasNames[i] ) );
3837  }
3838 
3839  aFormatter.Print( 0, "\n" );
3840  }
3841 
3842  wxArrayString footprints = aSymbol->GetFootprints();
3843 
3844  // Write the footprint filter list
3845  if( footprints.GetCount() != 0 )
3846  {
3847  aFormatter.Print( 0, "$FPLIST\n" );
3848 
3849  for( unsigned i = 0; i < footprints.GetCount(); i++ )
3850  {
3851  aFormatter.Print( 0, " %s\n", TO_UTF8( footprints[i] ) );
3852  }
3853 
3854  aFormatter.Print( 0, "$ENDFPLIST\n" );
3855  }
3856 
3857  // Save graphics items (including pins)
3858  if( !aSymbol->GetDrawItems().empty() )
3859  {
3860  // Sort the draw items in order to editing a file editing by hand.
3861  aSymbol->GetDrawItems().sort();
3862 
3863  aFormatter.Print( 0, "DRAW\n" );
3864 
3865  for( LIB_ITEM& item : aSymbol->GetDrawItems() )
3866  {
3867  switch( item.Type() )
3868  {
3869  case LIB_FIELD_T: // Fields have already been saved above.
3870  continue;
3871 
3872  case LIB_ARC_T:
3873  saveArc( (LIB_ARC*) &item, aFormatter );
3874  break;
3875 
3876  case LIB_BEZIER_T:
3877  saveBezier( (LIB_BEZIER*) &item, aFormatter );
3878  break;
3879 
3880  case LIB_CIRCLE_T:
3881  saveCircle( ( LIB_CIRCLE* ) &item, aFormatter );
3882  break;
3883 
3884  case LIB_PIN_T:
3885  savePin( (LIB_PIN* ) &item, aFormatter );
3886  break;
3887 
3888  case LIB_POLYLINE_T:
3889  savePolyLine( ( LIB_POLYLINE* ) &item, aFormatter );
3890  break;
3891 
3892  case LIB_RECTANGLE_T:
3893  saveRectangle( ( LIB_RECTANGLE* ) &item, aFormatter );
3894  break;
3895 
3896  case LIB_TEXT_T:
3897  saveText( ( LIB_TEXT* ) &item, aFormatter );
3898  break;
3899 
3900  default:
3901  ;
3902  }
3903  }
3904 
3905  aFormatter.Print( 0, "ENDDRAW\n" );
3906  }
3907 
3908  aFormatter.Print( 0, "ENDDEF\n" );
3909 }
3910 
3911 
3913  OUTPUTFORMATTER& aFormatter )
3914 {
3915  wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." );
3916 
3917  int x1 = aArc->GetFirstRadiusAngle();
3918 
3919  if( x1 > 1800 )
3920  x1 -= 3600;
3921 
3922  int x2 = aArc->GetSecondRadiusAngle();
3923 
3924  if( x2 > 1800 )
3925  x2 -= 3600;
3926 
3927  aFormatter.Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n",
3928  Iu2Mils( aArc->GetPosition().x ), Iu2Mils( aArc->GetPosition().y ),
3929  Iu2Mils( aArc->GetRadius() ), x1, x2, aArc->GetUnit(), aArc->GetConvert(),
3930  Iu2Mils( aArc->GetWidth() ), fill_tab[aArc->GetFillMode()],
3931  Iu2Mils( aArc->GetStart().x ), Iu2Mils( aArc->GetStart().y ),
3932  Iu2Mils( aArc->GetEnd().x ), Iu2Mils( aArc->GetEnd().y ) );
3933 }
3934 
3935 
3937  OUTPUTFORMATTER& aFormatter )
3938 {
3939  wxCHECK_RET( aBezier && aBezier->Type() == LIB_BEZIER_T, "Invalid LIB_BEZIER object." );
3940 
3941  aFormatter.Print( 0, "B %u %d %d %d", (unsigned)aBezier->GetPoints().size(),
3942  aBezier->GetUnit(), aBezier->GetConvert(), Iu2Mils( aBezier->GetWidth() ) );
3943 
3944  for( const auto& pt : aBezier->GetPoints() )
3945  aFormatter.Print( 0, " %d %d", Iu2Mils( pt.x ), Iu2Mils( pt.y ) );
3946 
3947  aFormatter.Print( 0, " %c\n", fill_tab[aBezier->GetFillMode()] );
3948 }
3949 
3950 
3952  OUTPUTFORMATTER& aFormatter )
3953 {
3954  wxCHECK_RET( aCircle && aCircle->Type() == LIB_CIRCLE_T, "Invalid LIB_CIRCLE object." );
3955 
3956  aFormatter.Print( 0, "C %d %d %d %d %d %d %c\n",
3957  Iu2Mils( aCircle->GetPosition().x ), Iu2Mils( aCircle->GetPosition().y ),
3958  Iu2Mils( aCircle->GetRadius() ), aCircle->GetUnit(), aCircle->GetConvert(),
3959  Iu2Mils( aCircle->GetWidth() ), fill_tab[aCircle->GetFillMode()] );
3960 }
3961 
3962 
3964  OUTPUTFORMATTER& aFormatter )
3965 {
3966  wxCHECK_RET( aField && aField->Type() == LIB_FIELD_T, "Invalid LIB_FIELD object." );
3967 
3968  int hjustify, vjustify;
3969  int id = aField->GetId();
3970  wxString text = aField->GetText();
3971 
3972  hjustify = 'C';
3973 
3974  if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
3975  hjustify = 'L';
3976  else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
3977  hjustify = 'R';
3978 
3979  vjustify = 'C';
3980 
3981  if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
3982  vjustify = 'B';
3983  else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
3984  vjustify = 'T';
3985 
3986  aFormatter.Print( 0, "F%d %s %d %d %d %c %c %c %c%c%c",
3987  id,
3988  EscapedUTF8( text ).c_str(), // wraps in quotes
3989  Iu2Mils( aField->GetTextPos().x ), Iu2Mils( aField->GetTextPos().y ),
3990  Iu2Mils( aField->GetTextWidth() ),
3991  aField->GetTextAngle() == 0 ? 'H' : 'V',
3992  aField->IsVisible() ? 'V' : 'I',
3993  hjustify, vjustify,
3994  aField->IsItalic() ? 'I' : 'N',
3995  aField->IsBold() ? 'B' : 'N' );
3996 
3997  /* Save field name, if necessary
3998  * Field name is saved only if it is not the default name.
3999  * Just because default name depends on the language and can change from
4000  * a country to another
4001  */
4002  wxString defName = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
4003 
4004  if( id >= FIELD1 && !aField->m_name.IsEmpty() && aField->m_name != defName )
4005  aFormatter.Print( 0, " %s", EscapedUTF8( aField->m_name ).c_str() );
4006 
4007  aFormatter.Print( 0, "\n" );
4008 }
4009 
4010 
4012  OUTPUTFORMATTER& aFormatter )
4013 {
4014  wxCHECK_RET( aPin && aPin->Type() == LIB_PIN_T, "Invalid LIB_PIN object." );
4015 
4016  int Etype;
4017 
4018  switch( aPin->GetType() )
4019  {
4020  default:
4022  Etype = 'I';
4023  break;
4024 
4026  Etype = 'O';
4027  break;
4028 
4030  Etype = 'B';
4031  break;
4032 
4034  Etype = 'T';
4035  break;
4036 
4038  Etype = 'P';
4039  break;
4040 
4042  Etype = 'U';
4043  break;
4044 
4046  Etype = 'W';
4047  break;
4048 
4050  Etype = 'w';
4051  break;
4052 
4054  Etype = 'C';
4055  break;
4056 
4058  Etype = 'E';
4059  break;
4060 
4062  Etype = 'N';
4063  break;
4064  }
4065 
4066  if( !aPin->GetName().IsEmpty() )
4067  aFormatter.Print( 0, "X %s", TO_UTF8( aPin->GetName() ) );
4068  else
4069  aFormatter.Print( 0, "X ~" );
4070 
4071  aFormatter.Print( 0, " %s %d %d %d %c %d %d %d %d %c",
4072  aPin->GetNumber().IsEmpty() ? "~" : TO_UTF8( aPin->GetNumber() ),
4073  Iu2Mils( aPin->GetPosition().x ), Iu2Mils( aPin->GetPosition().y ),
4074  Iu2Mils( (int) aPin->GetLength() ), (int) aPin->GetOrientation(),
4075  Iu2Mils( aPin->GetNumberTextSize() ), Iu2Mils( aPin->GetNameTextSize() ),
4076  aPin->GetUnit(), aPin->GetConvert(), Etype );
4077 
4078  if( aPin->GetShape() != GRAPHIC_PINSHAPE::LINE || !aPin->IsVisible() )
4079  aFormatter.Print( 0, " " );
4080 
4081  if( !aPin->IsVisible() )
4082  aFormatter.Print( 0, "N" );
4083 
4084  switch( aPin->GetShape() )
4085  {
4087  break;
4088 
4090  aFormatter.Print( 0, "I" );
4091  break;
4092 
4094  aFormatter.Print( 0, "C" );
4095  break;
4096 
4098  aFormatter.Print( 0, "IC" );
4099  break;
4100 
4102  aFormatter.Print( 0, "L" );
4103  break;
4104 
4106  aFormatter.Print( 0, "CL" );
4107  break;
4108 
4110  aFormatter.Print( 0, "V" );
4111  break;
4112 
4114  aFormatter.Print( 0, "F" );
4115  break;
4116 
4118  aFormatter.Print( 0, "X" );
4119  break;
4120 
4121  default:
4122  assert( !"Invalid pin shape" );
4123  }
4124 
4125  aFormatter.Print( 0, "\n" );
4126 
4127  aPin->ClearFlags( IS_CHANGED );
4128 }
4129 
4130 
4132  OUTPUTFORMATTER& aFormatter )
4133 {
4134  wxCHECK_RET( aPolyLine && aPolyLine->Type() == LIB_POLYLINE_T, "Invalid LIB_POLYLINE object." );
4135 
4136  int ccount = aPolyLine->GetCornerCount();
4137 
4138  aFormatter.Print( 0, "P %d %d %d %d", ccount, aPolyLine->GetUnit(), aPolyLine->GetConvert(),
4139  Iu2Mils( aPolyLine->GetWidth() ) );
4140 
4141  for( const auto& pt : aPolyLine->GetPolyPoints() )
4142  {
4143  aFormatter.Print( 0, " %d %d", Iu2Mils( pt.x ), Iu2Mils( pt.y ) );
4144  }
4145 
4146  aFormatter.Print( 0, " %c\n", fill_tab[aPolyLine->GetFillMode()] );
4147 }
4148 
4149 
4151  OUTPUTFORMATTER& aFormatter )
4152 {
4153  wxCHECK_RET( aRectangle && aRectangle->Type() == LIB_RECTANGLE_T,
4154  "Invalid LIB_RECTANGLE object." );
4155 
4156  aFormatter.Print( 0, "S %d %d %d %d %d %d %d %c\n",
4157  Iu2Mils( aRectangle->GetPosition().x ),
4158  Iu2Mils( aRectangle->GetPosition().y ),
4159  Iu2Mils( aRectangle->GetEnd().x ), Iu2Mils( aRectangle->GetEnd().y ),
4160  aRectangle->GetUnit(), aRectangle->GetConvert(),
4161  Iu2Mils( aRectangle->GetWidth() ), fill_tab[aRectangle->GetFillMode()] );
4162 }
4163 
4164 
4166  OUTPUTFORMATTER& aFormatter )
4167 {
4168  wxCHECK_RET( aText && aText->Type() == LIB_TEXT_T, "Invalid LIB_TEXT object." );
4169 
4170  wxString text = aText->GetText();
4171 
4172  if( text.Contains( wxT( " " ) ) || text.Contains( wxT( "~" ) ) || text.Contains( wxT( "\"" ) ) )
4173  {
4174  // convert double quote to similar-looking two apostrophes
4175  text.Replace( wxT( "\"" ), wxT( "''" ) );
4176  text = wxT( "\"" ) + text + wxT( "\"" );
4177  }
4178 
4179  aFormatter.Print( 0, "T %g %d %d %d %d %d %d %s", aText->GetTextAngle(),
4180  Iu2Mils( aText->GetTextPos().x ), Iu2Mils( aText->GetTextPos().y ),
4181  Iu2Mils( aText->GetTextWidth() ), !aText->IsVisible(),
4182  aText->GetUnit(), aText->GetConvert(), TO_UTF8( text ) );
4183 
4184  aFormatter.Print( 0, " %s %d", aText->IsItalic() ? "Italic" : "Normal", aText->IsBold() );
4185 
4186  char hjustify = 'C';
4187 
4188  if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
4189  hjustify = 'L';
4190  else if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
4191  hjustify = 'R';
4192 
4193  char vjustify = 'C';
4194 
4195  if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
4196  vjustify = 'B';
4197  else if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
4198  vjustify = 'T';
4199 
4200  aFormatter.Print( 0, " %c %c\n", hjustify, vjustify );
4201 }
4202 
4203 
4205 {
4206  wxFileName fileName = m_libFileName;
4207 
4208  fileName.SetExt( DOC_EXT );
4209  FILE_OUTPUTFORMATTER formatter( fileName.GetFullPath() );
4210 
4211  formatter.Print( 0, "%s\n", DOCFILE_IDENT );
4212 
4213  for( LIB_PART_MAP::iterator it = m_symbols.begin(); it != m_symbols.end(); ++it )
4214  {
4215  wxString description = it->second->GetDescription();
4216  wxString keyWords = it->second->GetKeyWords();
4217  wxString docFileName = it->second->GetDocFileName();
4218 
4219  if( description.IsEmpty() && keyWords.IsEmpty() && docFileName.IsEmpty() )
4220  continue;
4221 
4222  formatter.Print( 0, "#\n$CMP %s\n", TO_UTF8( it->second->GetName() ) );
4223 
4224  if( !description.IsEmpty() )
4225  formatter.Print( 0, "D %s\n", TO_UTF8( description ) );
4226 
4227  if( !keyWords.IsEmpty() )
4228  formatter.Print( 0, "K %s\n", TO_UTF8( keyWords ) );
4229 
4230  if( !docFileName.IsEmpty() )
4231  formatter.Print( 0, "F %s\n", TO_UTF8( docFileName ) );
4232 
4233  formatter.Print( 0, "$ENDCMP\n" );
4234  }
4235 
4236  formatter.Print( 0, "#\n#End Doc Library\n" );
4237 }
4238 
4239 
4240 void SCH_LEGACY_PLUGIN_CACHE::DeleteSymbol( const wxString& aSymbolName )
4241 {
4242  LIB_PART_MAP::iterator it = m_symbols.find( aSymbolName );
4243 
4244  if( it == m_symbols.end() )
4245  THROW_IO_ERROR( wxString::Format( _( "library %s does not contain a symbol named %s" ),
4246  m_libFileName.GetFullName(), aSymbolName ) );
4247 
4248  LIB_PART* part = it->second;
4249 
4250  if( part->IsRoot() )
4251  {
4252  LIB_PART* rootPart = part;
4253 
4254  // Remove the root symbol and all it's children.
4255  m_symbols.erase( it );
4256 
4257  LIB_PART_MAP::iterator it1 = m_symbols.begin();
4258 
4259  while( it1 != m_symbols.end() )
4260  {
4261  if( it1->second->IsAlias() && it1->second->GetParent().lock() == rootPart->SharedPtr() )
4262  {
4263  delete it1->second;
4264  it1 = m_symbols.erase( it1 );
4265  }
4266  else
4267  {
4268  it1++;
4269  }
4270  }
4271 
4272  delete rootPart;
4273  }
4274  else
4275  {
4276  // Just remove the alias.
4277  m_symbols.erase( it );
4278  delete part;
4279  }
4280 
4281  ++m_modHash;
4282  m_isModified = true;
4283 }
4284 
4285 
4286 void SCH_LEGACY_PLUGIN::cacheLib( const wxString& aLibraryFileName )
4287 {
4288  if( !m_cache || !m_cache->IsFile( aLibraryFileName ) || m_cache->IsFileChanged() )
4289  {
4290  // a spectacular episode in memory management:
4291  delete m_cache;
4292  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryFileName );
4293 
4294  // Because m_cache is rebuilt, increment PART_LIBS::s_modify_generation
4295  // to modify the hash value that indicate component to symbol links
4296  // must be updated.
4298 
4299  if( !isBuffering( m_props ) )
4300  m_cache->Load();
4301  }
4302 }
4303 
4304 
4306 {
4307  std::string propName( SCH_LEGACY_PLUGIN::PropNoDocFile );
4308 
4309  if( aProperties && aProperties->find( propName ) != aProperties->end() )
4310  return false;
4311 
4312  return true;
4313 }
4314 
4315 
4316 bool SCH_LEGACY_PLUGIN::isBuffering( const PROPERTIES* aProperties )
4317 {
4318  return ( aProperties && aProperties->Exists( SCH_LEGACY_PLUGIN::PropBuffering ) );
4319 }
4320 
4321 
4323 {
4324  if( m_cache )
4325  return m_cache->GetModifyHash();
4326 
4327  // If the cache hasn't been loaded, it hasn't been modified.
4328  return 0;
4329 }
4330 
4331 
4332 void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
4333  const wxString& aLibraryPath,
4334  const PROPERTIES* aProperties )
4335 {
4336  LOCALE_IO toggle; // toggles on, then off, the C locale.
4337 
4338  m_props = aProperties;
4339 
4340  bool powerSymbolsOnly = ( aProperties &&
4341  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
4342  cacheLib( aLibraryPath );
4343 
4344  const LIB_PART_MAP& symbols = m_cache->m_symbols;
4345 
4346  for( LIB_PART_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
4347  {
4348  if( !powerSymbolsOnly || it->second->IsPower() )
4349  aSymbolNameList.Add( it->first );
4350  }
4351 }
4352 
4353 
4354 void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( std::vector<LIB_PART*>& aSymbolList,
4355  const wxString& aLibraryPath,
4356  const PROPERTIES* aProperties )
4357 {
4358  LOCALE_IO toggle; // toggles on, then off, the C locale.
4359 
4360  m_props = aProperties;
4361 
4362  bool powerSymbolsOnly = ( aProperties &&
4363  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
4364  cacheLib( aLibraryPath );
4365 
4366  const LIB_PART_MAP& symbols = m_cache->m_symbols;
4367 
4368  for( LIB_PART_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
4369  {
4370  if( !powerSymbolsOnly || it->second->IsPower() )
4371  aSymbolList.push_back( it->second );
4372  }
4373 }
4374 
4375 
4376 LIB_PART* SCH_LEGACY_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
4377  const PROPERTIES* aProperties )
4378 {
4379  LOCALE_IO toggle; // toggles on, then off, the C locale.
4380 
4381  m_props = aProperties;
4382 
4383  cacheLib( aLibraryPath );
4384 
4385  LIB_PART_MAP::const_iterator it = m_cache->m_symbols.find( aSymbolName );
4386 
4387  if( it == m_cache->m_symbols.end() )
4388  return nullptr;
4389 
4390  return it->second;
4391 }
4392 
4393 
4394 void SCH_LEGACY_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_PART* aSymbol,
4395  const PROPERTIES* aProperties )
4396 {
4397  m_props = aProperties;
4398 
4399  cacheLib( aLibraryPath );
4400 
4401  m_cache->AddSymbol( aSymbol );
4402 
4403  if( !isBuffering( aProperties ) )
4404  m_cache->Save( writeDocFile( aProperties ) );
4405 }
4406 
4407 
4408 void SCH_LEGACY_PLUGIN::DeleteSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
4409  const PROPERTIES* aProperties )
4410 {
4411  m_props = aProperties;
4412 
4413  cacheLib( aLibraryPath );
4414 
4415  m_cache->DeleteSymbol( aSymbolName );
4416 
4417  if( !isBuffering( aProperties ) )
4418  m_cache->Save( writeDocFile( aProperties ) );
4419 }
4420 
4421 
4422 void SCH_LEGACY_PLUGIN::CreateSymbolLib( const wxString& aLibraryPath,
4423  const PROPERTIES* aProperties )
4424 {
4425  if( wxFileExists( aLibraryPath ) )
4426  {
4428  _( "symbol library \"%s\" already exists, cannot create a new library" ),
4429  aLibraryPath.GetData() ) );
4430  }
4431 
4432  LOCALE_IO toggle;
4433 
4434  m_props = aProperties;
4435 
4436  delete m_cache;
4437  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
4438  m_cache->SetModified();
4439  m_cache->Save( writeDocFile( aProperties ) );
4440  m_cache->Load(); // update m_writable and m_mod_time
4441 }
4442 
4443 
4444 bool SCH_LEGACY_PLUGIN::DeleteSymbolLib( const wxString& aLibraryPath,
4445  const PROPERTIES* aProperties )
4446 {
4447  wxFileName fn = aLibraryPath;
4448 
4449  if( !fn.FileExists() )
4450  return false;
4451 
4452  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
4453  // we don't want that. we want bare metal portability with no UI here.
4454  if( wxRemove( aLibraryPath ) )
4455  {
4456  THROW_IO_ERROR( wxString::Format( _( "library \"%s\" cannot be deleted" ),
4457  aLibraryPath.GetData() ) );
4458  }
4459 
4460  if( m_cache && m_cache->IsFile( aLibraryPath ) )
4461  {
4462  delete m_cache;
4463  m_cache = 0;
4464  }
4465 
4466  return true;
4467 }
4468 
4469 
4470 void SCH_LEGACY_PLUGIN::SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties )
4471 {
4472  if( !m_cache )
4473  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
4474 
4475  wxString oldFileName = m_cache->GetFileName();
4476 
4477  if( !m_cache->IsFile( aLibraryPath ) )
4478  {
4479  m_cache->SetFileName( aLibraryPath );
4480  }
4481 
4482  // This is a forced save.
4483  m_cache->SetModified();
4484  m_cache->Save( writeDocFile( aProperties ) );
4485  m_cache->SetFileName( oldFileName );
4486 }
4487 
4488 
4489 bool SCH_LEGACY_PLUGIN::CheckHeader( const wxString& aFileName )
4490 {
4491  // Open file and check first line
4492  wxTextFile tempFile;
4493 
4494  tempFile.Open( aFileName );
4495  wxString firstline;
4496  // read the first line
4497  firstline = tempFile.GetFirstLine();
4498  tempFile.Close();
4499 
4500  return firstline.StartsWith( "EESchema" );
4501 }
4502 
4503 
4504 bool SCH_LEGACY_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath )
4505 {
4506  return wxFileName::IsFileWritable( aLibraryPath );
4507 }
4508 
4509 
4511  int aMinorVersion )
4512 {
4513  return SCH_LEGACY_PLUGIN_CACHE::LoadPart( reader, aMajorVersion, aMinorVersion );
4514 }
4515 
4516 
4518 {
4519  SCH_LEGACY_PLUGIN_CACHE::SaveSymbol( part, formatter );
4520 }
4521 
4522 
4523 
4524 const char* SCH_LEGACY_PLUGIN::PropBuffering = "buffering";
4525 const char* SCH_LEGACY_PLUGIN::PropNoDocFile = "no_doc_file";
static LIB_POLYLINE * loadPolyLine(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
void SetTextAngle(double aAngle)
Definition: eda_text.h:150
#define TEXT_ANGLE_HORIZ
Class for a bus to bus entry.
SCH_SHEET * loadSheet(LINE_READER &aReader)
wxString GetName(bool aTranslate=true) const
Returns the field name.
Definition: lib_field.cpp:366
CITER next(CITER it)
Definition: ptree.cpp:130
power input (GND, VCC for ICs). Must be connected to a power output.
void LoadContent(LINE_READER &aReader, SCH_SCREEN *aScreen, int version=EESCHEMA_VERSION)
static const char * GetLineStyleName(PLOT_DASH_TYPE aStyle)
Definition: sch_line.cpp:121
bool IsBold() const
Definition: eda_text.h:167
SCH_JUNCTION * loadJunction(LINE_READER &aReader)
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
void DeleteSymbol(const wxString &aName)
SCH_SHEET * Load(const wxString &aFileName, KIWAY *aKiway, SCH_SHEET *aAppendToMe=nullptr, const PROPERTIES *aProperties=nullptr) override
Load information from some input file format that this SCH_PLUGIN implementation knows about,...
COLOR4D GetLineColor() const
Definition: sch_line.cpp:255
void init(KIWAY *aKiway, const PROPERTIES *aProperties=nullptr)
initialize PLUGIN like a constructor would.
int m_nameTextSize
Pin num and Pin name sizes.
Definition: lib_pin.h:77
const wxString & GetFileName() const
Definition: sch_screen.h:157
static LIB_TEXT * loadText(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader, int aMajorVersion, int aMinorVersion)
LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived to re...
Definition: richio.h:81
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:194
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:540
int m_ScreenNumber
Definition: base_screen.h:135
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:139
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:184
bool IsGraphicLine() const
Returns if the line is a graphic (non electrical line)
Definition: sch_line.cpp:815
name of datasheet
static void saveCircle(LIB_CIRCLE *aCircle, OUTPUTFORMATTER &aFormatter)
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:62
GRAPHIC_PINSHAPE m_shape
Shape drawn around pin.
Definition: lib_pin.h:70
int GetPinNameOffset()
int y2
Definition: transform.h:51
virtual const wxString & GetSource() const
Function GetSource returns the name of the source of the lines in an abstract sense.
Definition: richio.h:130
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:90
void SaveSymbol(const wxString &aLibraryPath, const LIB_PART *aSymbol, const PROPERTIES *aProperties=nullptr) override
Write aSymbol to an existing library located at aLibraryPath.
wxPoint GetStartPoint() const
Definition: sch_line.h:97
void SetPosition(const wxPoint &aPosition)
Definition: lib_item.h:251
wxString GetName() const override
wxPoint GetEnd() const
Definition: lib_rectangle.h:89
int GetPenSizeForBold(int aTextSize)
Function GetPensizeForBold.
Definition: gr_text.cpp:66
wxString m_error
For throwing exceptions or errors on partial schematic loads.
#define TEXT_ANGLE_VERT
static int s_modify_generation
helper for GetModifyHash()
This file is part of the common library.
int m_numTextSize
Definition: lib_pin.h:76
#define LIBFILE_IDENT
Definition: class_library.h:60
wxPoint GetPosition() const override
Function GetPosition.
void SetRevision(const wxString &aRevision)
Definition: title_block.h:84
Define a symbol library graphical text item.
Definition: lib_text.h:40
void saveLine(SCH_LINE *aLine)
SCH_COMPONENT * loadComponent(LINE_READER &aReader)
int GetOrientation() const
Definition: lib_pin.h:204
static void loadDrawEntries(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader, int aMajorVersion, int aMinorVersion)
const wxString & GetComment(int aIdx) const
Definition: title_block.h:110
int GetHeightMils() const
Definition: page_info.h:140
timestamp_t GetDateLastEdition() const
VTBL_ENTRY PROJECT & Prj() const
Function Prj returns the PROJECT associated with this KIWAY.
Definition: kiway.cpp:171
bool IsVisible() const
Definition: eda_text.h:170
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:216
SCH_LEGACY_PLUGIN_CACHE * m_cache
bool empty(int aType=UNDEFINED_TYPE)
Definition: multivector.h:237
static uint32_t parseHex(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parse an ASCII hex integer string with possible leading whitespace into a long integer and updates th...
void SetItalic(bool isItalic)
Definition: eda_text.h:163
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
int color
Definition: DXF_plotter.cpp:61
Field object used in symbol libraries.
Definition: lib_field.h:59
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:111
const wxChar *const traceSchLegacyPlugin
Flag to enable legacy schematic plugin debug output.
EE_TYPE OfType(KICAD_T aType)
Definition: sch_rtree.h:219
double GetScale() const
Definition: bitmap_base.h:92
std::map< wxString, LIB_PART *, LibPartMapSort > LIB_PART_MAP
Part map used by part library object.
pin for passive components: must be connected, and can be connected to any pin
wxImage * GetImageData()
Definition: bitmap_base.h:83
void SetVisible(bool aVisible)
Definition: eda_text.h:169
void sort()
Definition: multivector.h:242
void SetFirstRadiusAngle(int aAngle)
Definition: lib_arc.h:107
FILL_T GetFillMode() const
Definition: lib_item.h:306
bool SetType(const wxString &aStandardPageDescriptionName, bool aIsPortrait=false)
Function SetType sets the name of the page type and also the sizes and margins commonly associated wi...
Definition: page_info.cpp:117
int x2
Definition: transform.h:50
static void parseQuotedString(wxString &aString, LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken=NULL, bool aCanBeEmpty=false)
Parse an quoted ASCII utf8 and updates the pointer at aOutput if it is not NULL.
SCH_SHEET * m_rootSheet
The root sheet of the schematic being loaded..
wxString GetLogicalName() const
wxString GetPrefix() const
double GetTextAngle() const
Definition: eda_text.h:158
int GetId() const
Definition: sch_field.h:108
SCH_SHEET * GetRootSheet()
Return the root sheet of this SCH_SHEET object.
Definition: sch_sheet.cpp:143
LIB_FIELD & GetValueField()
Return reference to the value field.
wxPoint GetPosition() const override
Definition: lib_circle.h:76
unknown electrical properties: creates always a warning when connected
static double parseDouble(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parses an ASCII point string with possible leading whitespace into a double precision floating point ...
void Format(SCH_SCREEN *aScreen)
void saveText(SCH_TEXT *aText)
#define LIB_VERSION_MINOR
Definition: class_library.h:57
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Definition: title_block.h:74
const TITLE_BLOCK & GetTitleBlock() const
Definition: sch_screen.h:162
SCH_LEGACY_PLUGIN_CACHE(const wxString &aLibraryPath)
int m_Unit
Unit identification for multiple parts per package.
Definition: lib_item.h:81
OUTPUTFORMATTER is an important interface (abstract class) used to output 8 bit text in a convenient ...
Definition: richio.h:327
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:153
#define LIB_VERSION(major, minor)
Definition: class_library.h:62
wxString m_name
Definition: lib_pin.h:74
int GetThickness() const
Return the pen width.
Definition: eda_text.h:148
int x1
Definition: transform.h:48
static const wxString GetDefaultFieldName(int aFieldNdx)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
#define MAX_UNIT_COUNT_PER_PACKAGE
The maximum number of units per package.
Definition: eeschema_id.h:44
static void savePin(LIB_PIN *aPin, OUTPUTFORMATTER &aFormatter)
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:78
const wxString & GetType() const
Definition: page_info.h:97
static LIB_CIRCLE * loadCircle(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:222
static void parseUnquotedString(wxString &aString, LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken=NULL, bool aCanBeEmpty=false)
Parse an unquoted utf8 string and updates the pointer at aOutput if it is not NULL.
#define SCH_LAYER_ID_COUNT
int GetId() const
Definition: lib_field.h:135
void saveNoConnect(SCH_NO_CONNECT *aNoConnect)
static void saveBezier(LIB_BEZIER *aBezier, OUTPUTFORMATTER &aFormatter)
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
bool IsCustom() const
Function IsCustom returns true if the type is Custom.
Definition: page_info.cpp:176
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:252
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_bitmap.h:140
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
void loadHeader(FILE_LINE_READER &aReader)
int GetWidth() const override
Definition: lib_circle.h:88
static LIB_PART * ParsePart(LINE_READER &aReader, int majorVersion=0, int minorVersion=0)
void SetWidth(int aWidth) override
Definition: lib_polyline.h:105
int m_length
Length of the pin.
Definition: lib_pin.h:68
std::chrono::steady_clock CLOCK
SCH_SCREEN * GetScreen()
Definition: sch_sheet.h:278
#define Mils2Iu(x)
TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout,...
Definition: title_block.h:40
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:152
#define T_WIDTH
int GetDefaultWidth() const
Definition: sch_line.cpp:296
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
Field Reference of part, i.e. "IC21".
void saveSheet(SCH_SHEET *aSheet)
const wxArrayString & GetPathsAndReferences() const
static void saveField(LIB_FIELD *aField, OUTPUTFORMATTER &aFormatter)
SCH_BUS_ENTRY_BASE * loadBusEntry(LINE_READER &aReader)
int GetWidth() const override
Definition: lib_polyline.h:104
unsigned GetCornerCount() const
Definition: lib_polyline.h:73
virtual EDA_ITEM * Clone() const
Function Clone creates a duplicate of this item with linked list members set to NULL.
The base class for drawable items used by schematic library components.
Definition: lib_item.h:60
void SetWidth(int aWidth) override
Definition: lib_arc.h:102
A cache assistant for the part library portion of the SCH_PLUGIN API, and only for the SCH_LEGACY_PLU...
void saveField(SCH_FIELD *aField)
#define T_STYLE
std::string EscapedUTF8(wxString aString)
Function EscapedUTF8 returns an 8 bit UTF8 string given aString in unicode form.
Definition: string.cpp:249
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:41
void AddDrawItem(LIB_ITEM *aItem)
Add a new draw aItem to the draw object list.
void saveJunction(SCH_JUNCTION *aJunction)
#define LIB_VERSION_MAJOR
Definition: class_library.h:56
int m_version
Version of file being loaded.
void loadFile(const wxString &aFileName, SCH_SCREEN *aScreen)
int GetWidth() const override
Definition: lib_bezier.h:92
bool IsItalic() const
Definition: eda_text.h:164
#define SCHEMATIC_HEAD_STRING
Definition: general.h:43
const std::vector< wxPoint > & GetPolyPoints() const
Definition: lib_polyline.h:60
void DeleteSymbol(const wxString &aLibraryPath, const wxString &aSymbolName, const PROPERTIES *aProperties=nullptr) override
Delete the entire LIB_PART associated with aAliasName from the library aLibraryPath.
void Reserve(size_t aCount)
Definition: lib_bezier.h:61
int GetFileNameSize() const
Definition: sch_sheet.h:275
wxString m_path
Root project path for loading child sheets.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
int y1
Definition: transform.h:49
bool ShowPinNames()
int GetSecondRadiusAngle() const
Definition: lib_arc.h:111
#define EESCHEMA_VERSION
Definition: general.h:42
int m_orientation
Pin orientation (Up, Down, Left, Right)
Definition: lib_pin.h:69
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
int GetUnit() const
Definition: lib_item.h:300
PLOT_DASH_TYPE GetDefaultStyle() const
Definition: sch_line.cpp:263
#define VALUE
int GetUnit() const
int GetSheetNameSize() const
Definition: sch_sheet.h:272
#define IS_CHANGED
std::function passed to nested users by ref, avoids copying std::function
Definition: base_struct.h:116
bool ShowPinNumbers()
FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
LIB_PART * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=nullptr) override
Load a LIB_PART object having aPartName from the aLibraryPath containing a library format that this S...
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
#define DOCFILE_IDENT
wxString m_number
Definition: lib_pin.h:75
LIB_FIELD & GetReferenceField()
Return reference to the reference designator field.
bool isBuffering(const PROPERTIES *aProperties)
void SetEnd(const wxPoint &aPoint)
Definition: lib_arc.h:117
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:183
LIB_FIELD * FindField(const wxString &aFieldName)
Find a field within this part matching aFieldName and returns it or NULL if not found.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:111
void SetComment(int aIdx, const wxString &aComment)
Definition: title_block.h:104
wxString GetName() const
Definition: sch_sheet.h:269
#define NULL
int GetUnitCount() const override
For items with units, return the number of units.
BITMAP_BASE * GetImage()
Definition: sch_bitmap.h:59
void SetWidth(int aWidth) override
Definition: lib_rectangle.h:86
void loadHierarchy(SCH_SHEET *aSheet)
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
virtual unsigned LineNumber() const
Function Line Number returns the line number of the last line read from this LINE_READER.
Definition: richio.h:159
const wxString & GetRevision() const
Definition: title_block.h:89
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_junction.h:100
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:216
void Reserve(size_t aPointCount)
Definition: lib_polyline.h:57
static void loadField(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
static void saveText(LIB_TEXT *aText, OUTPUTFORMATTER &aFormatter)
const wxString & GetName() const
Definition: lib_pin.h:149
PLOT_DASH_TYPE GetLineStyle() const
Definition: sch_line.cpp:287
static void saveRectangle(LIB_RECTANGLE *aRectangle, OUTPUTFORMATTER &aFormatter)
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
PAGE_INFO describes the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:54
TRANSFORM & GetTransform() const
#define PIN_INVISIBLE
Definition: lib_pin.h:46
Class LIB_PIN definition.
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:187
const wxString & GetCompany() const
Definition: title_block.h:99
static char parseChar(LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken=NULL)
Parse a single ASCII character and updates the pointer at aOutput if it is not NULL.
wxString GetText(GRAPHIC_PINSHAPE aShape)
Definition: pin_shape.cpp:58
void SetDescription(const wxString &aDescription)
void SetDocFileName(const wxString &aDocFileName)
int GetWidth() const override
Definition: lib_rectangle.h:85
static bool is_eol(char c)
PART_SPTR SharedPtr()
wxPoint GetStart() const
Definition: lib_arc.h:113
void SetParent(LIB_PART *aParent=nullptr)
PART_REF & GetParent()
const int fill_tab[3]
Definition: lib_item.cpp:34
static void savePolyLine(LIB_POLYLINE *aPolyLine, OUTPUTFORMATTER &aFormatter)
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
void SetRadius(int aRadius)
Definition: lib_circle.h:91
void Empty()
Definition: eda_text.h:239
Define a library symbol object.
void SetCompany(const wxString &aCompany)
Definition: title_block.h:94
timestamp_t GetTimeStamp() const
Definition: base_struct.h:213
#define DOC_EXT
Definition: class_library.h:51
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:274
const std::vector< wxPoint > & GetPoints() const
Definition: lib_bezier.h:72
void loadPageSettings(LINE_READER &aReader, SCH_SCREEN *aScreen)
wxLogTrace helper definitions.
#define T_COLOR
void saveBitmap(SCH_BITMAP *aBitmap)
wxPoint GetLibPosition() const
Definition: sch_field.h:192
#define THROW_IO_ERROR(msg)
LABEL_SPIN_STYLE GetLabelSpinStyle() const
Definition: sch_text.h:238
SCH_LAYER_ID
Eeschema drawing layers.
static const char * PropNoDocFile
The property used internally by the plugin to disable writing the library documentation (....
bool IsVisible() const
Return the visibility status of the draw object.
Definition: lib_pin.h:343
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:75
#define USE_OLD_DOC_FILE_FORMAT(major, minor)
Definition: class_library.h:76
static void FormatPart(LIB_PART *aPart, OUTPUTFORMATTER &aFormatter)
int GetRadius() const
Definition: lib_circle.h:92
wxPoint m_End() const
int GetNameTextSize() const
Definition: lib_pin.h:175
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
void SetModified(bool aModified=true)
void AddPoint(const wxPoint &aPoint)
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: sch_screen.h:164
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.h:104
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:315
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_sheet.h:538
static int parseInt(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parse an ASCII integer string with possible leading whitespace into an integer and updates the pointe...
wxArrayString GetFootprints() const
void SetTitle(const wxString &aTitle)
Definition: title_block.h:60
int GetConvert() const
Definition: lib_item.h:303
static PLOT_DASH_TYPE GetLineStyleByName(const wxString &aStyleName)
Definition: sch_line.cpp:131
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:42
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
void saveComponent(SCH_COMPONENT *aComponent)
int GetFieldCount() const
Return the number of fields in this symbol.
UTF8 Format() const
Definition: lib_id.cpp:237
static void SaveSymbol(LIB_PART *aSymbol, OUTPUTFORMATTER &aFormatter, LIB_PART_MAP *aMap=nullptr)
void SaveLibrary(const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
int SetLibItemName(const UTF8 &aLibItemName, bool aTestForRev=true)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:206
void SetFillMode(FILL_T aFillMode)
Definition: lib_item.h:305
const char * delims
void SetSecondRadiusAngle(int aAngle)
Definition: lib_arc.h:110
bool CheckHeader(const wxString &aFileName) override
Return true if the first line in aFileName begins with the expected header.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:206
static LIB_RECTANGLE * loadRectangle(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
PLOT_DASH_TYPE
Enum for choosing dashed line type.
Definition: plotter.h:86
int GetRadius() const
Definition: lib_arc.h:105
void SetConvert(int aConvert)
Definition: lib_item.h:302
wxPoint GetPosition() const override
Definition: lib_pin.h:429
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:99
wxString GetFileName(void) const
Return the filename corresponding to this sheet.
Definition: sch_sheet.cpp:616
SCH_LAYER_ID GetLayer() const
Function GetLayer returns the layer this item is on.
Definition: sch_item.h:212
void SetFileName(const wxString &aFileName)
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:332
static void loadAliases(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader, LIB_PART_MAP *aMap=nullptr)
static LIB_BEZIER * loadBezier(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
SCH_BITMAP * loadBitmap(LINE_READER &aReader)
int m_attributes
Set bit 0 to indicate pin is invisible.
Definition: lib_pin.h:73
bool IsFile(const wxString &aFullPathAndFileName) const
const wxString & GetDate() const
Definition: title_block.h:79
const wxString & GetNumber() const
Definition: lib_pin.h:177
ELECTRICAL_PINTYPE GetType() const
Get the electrical type of the pin.
Definition: lib_pin.h:232
void SetUnit(int aUnit)
Definition: lib_item.h:299
int GetLineSize() const
Definition: sch_line.h:129
int GetWidth() const override
Definition: lib_arc.h:101
wxPoint m_position
Position of the pin.
Definition: lib_pin.h:67
static LIB_PART * LoadPart(LINE_READER &aReader, int aMajorVersion, int aMinorVersion, LIB_PART_MAP *aMap=nullptr)
int GetNumberTextSize() const
Definition: lib_pin.h:202
bool Exists(const std::string &aProperty) const
Definition: properties.h:44
int GetTextWidth() const
Definition: eda_text.h:226
virtual char * ReadLine()=0
Function ReadLine reads a line of text into the buffer and increments the line number counter.
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
bool IsPower() const
see class PGM_BASE
#define SCH_PARSE_ERROR(text, reader, pos)
static void loadFootprintFilters(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
void SetEnd(const wxPoint &aEnd)
Definition: lib_rectangle.h:88
void saveBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
COLOR4D GetDefaultColor() const
Definition: sch_line.cpp:225
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Adds a bus alias definition (and transfers ownership of the pointer)
Definition: sch_screen.cpp:901
const char * name
Definition: DXF_plotter.cpp:60
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:38
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
OUTPUTFORMATTER * m_out
The output formatter for saving SCH_SCREEN objects.
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:175
const std::map< PINSHEETLABEL_SHAPE, const char * > sheetLabelNames
bool IsPortrait() const
Definition: page_info.h:121
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:186
#define _(s)
Definition: 3d_actions.cpp:31
usual pin input: must be connected
void CreateSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
Create a new empty symbol library at aLibraryPath.
std::vector< LIB_FIELD > LIB_FIELDS
Definition: lib_field.h:214
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:371
static FILL_T parseFillMode(LINE_READER &aReader, const char *aLine, const char **aOutput)
void SetKeyWords(const wxString &aKeyWords)
void Save(const wxString &aFileName, SCH_SCREEN *aScreen, KIWAY *aKiway, const PROPERTIES *aProperties=nullptr) override
Write aSchematic to a storage file in a format that this SCH_PLUGIN implementation knows about,...
EE_RTREE & Items()
Definition: sch_screen.h:127
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
bool IsAlias() const
void SetRadius(int aRadius)
Definition: lib_arc.h:104
wxPoint GetEnd() const
Definition: lib_arc.h:116
SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:89
wxPoint GetPosition() const override
Function GetPosition.
static void saveArc(LIB_ARC *aArc, OUTPUTFORMATTER &aFormatter)
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
ELECTRICAL_PINTYPE m_type
Electrical type of the pin. See enum ELECTRICAL_PINTYPE.
Definition: lib_pin.h:72
void cacheLib(const wxString &aLibraryFileName)
static bool strCompare(const char *aString, const char *aLine, const char **aOutput=NULL)
Compare aString to the string starting at aLine and advances the character point to the end of String...
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType, bool aLib=false)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:352
FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
int m_Convert
Shape identification for alternate body styles.
Definition: lib_item.h:87
int GetModifyHash() const override
Return the modification hash from the library cache.
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:42
Class for a wire to bus entry.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:256
void SetWidth(int aWidth) override
Definition: lib_circle.h:89
int m_NumberOfScreens
Definition: base_screen.h:136
SCH_NO_CONNECT * loadNoConnect(LINE_READER &aReader)
const wxPoint & GetTextPos() const
Definition: eda_text.h:232
int GetFirstRadiusAngle() const
Definition: lib_arc.h:108
void SetStart(const wxPoint &aPoint)
Definition: lib_arc.h:114
int GetPenSize() const override
Function GetPenSize virtual pure.
Definition: sch_line.cpp:316
const wxString & GetTitle() const
Definition: title_block.h:65
input or output (like port for a microprocessor)
int GetConvert() const
LIB_PART * removeSymbol(LIB_PART *aAlias)
void loadHeader(LINE_READER &aReader, SCH_SCREEN *aScreen)
uint32_t timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:52
static LIB_PIN * loadPin(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
SCH_LINE * loadWire(LINE_READER &aReader)
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:155
KIWAY * m_kiway
Required for path to legacy component libraries.
Definition for part library class.
void SetId(int aId)
Definition: sch_field.h:110
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
wxString m_name
Name (not the field text value itself, that is .m_Text)
Definition: lib_field.h:62
static LIB_ARC * loadArc(std::unique_ptr< LIB_PART > &aPart, LINE_READER &aReader)
void SetModify()
Definition: base_screen.h:224
not connected (must be left open)
SCH_TEXT * loadText(LINE_READER &aReader)
void SetWidth(int aWidth) override
Definition: lib_bezier.h:93
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
#define T_COLORA
LIB_FIELD * GetField(int aId) const
Return pointer to the requested field.
const LIB_ID & GetLibId() const
int GetLength()
Definition: lib_pin.h:282
void SetBold(bool aBold)
Definition: eda_text.h:166
bool IsSymbolLibWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
void SetPortrait(bool aIsPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
Definition: page_info.cpp:182
void Save(bool aSaveDocFile=true)
Save the entire library to file m_libFileName;.
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
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:136
output of a regulator: intended to be connected to power input pins
void saveBusEntry(SCH_BUS_ENTRY_BASE *aBusEntry)
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
void AddPoint(const wxPoint &aPoint)
Definition: lib_bezier.h:62
static const char * PropPowerSymsOnly
wxSize GetSize()
Definition: sch_sheet.h:280
bool UnitsLocked() const
Check whether part units are interchangeable.
wxPoint GetPosition() const override
Definition: lib_rectangle.h:76
void AddSymbol(const LIB_PART *aPart)
std::unordered_set< std::shared_ptr< BUS_ALIAS > > GetBusAliases()
Returns a list of bus aliases defined in this screen.
Definition: sch_screen.h:471
bool writeDocFile(const PROPERTIES *aProperties)
wxFileName GetRealFile() const
int GetWidthMils() const
Definition: page_info.h:137
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
Populate a list of LIB_PART alias names contained within the library aLibraryPath.
void GetFields(LIB_FIELDS &aList)
Return a list of fields within this part.
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:243
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207
const PROPERTIES * m_props
Passed via Save() or Load(), no ownership, may be nullptr.
std::shared_ptr< BUS_ALIAS > loadBusAlias(LINE_READER &aReader, SCH_SCREEN *aScreen)
LIB_BEZIER defines bezier curve graphic body item.
Definition: lib_bezier.h:35
bool DeleteSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
Delete an existing symbol library and returns true if successful, or if library does not exist return...
wxPoint GetPosition() const override
Definition: lib_arc.h:92
wxPoint GetPosition() const override
Function GetPosition.
std::stack< wxString > m_currentPath
Stack to maintain nested sheet paths.
wxPoint GetEndPoint() const
Definition: sch_line.h:100