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