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