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