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