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