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 #include <pgm_base.h>
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 #include <confirm.h>
64 
65 
66 // Must be the first line of part library document (.dcm) files.
67 #define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
68 
69 #define SCH_PARSE_ERROR( text, reader, pos ) \
70  THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \
71  reader.LineNumber(), pos - reader.Line() )
72 
73 
74 // Token delimiters.
75 const char* delims = " \t\r\n";
76 
77 // Tokens to read/save graphic lines style
78 #define T_STYLE "style"
79 #define T_COLOR "rgb" // cannot be modifed (used by wxWidgets)
80 #define T_COLORA "rgba" // cannot be modifed (used by wxWidgets)
81 #define T_WIDTH "width"
82 
83 
84 static bool is_eol( char c )
85 {
86  // The default file eol character used internally by KiCad.
87  // |
88  // | Possible eol if someone edited the file by hand on certain platforms.
89  // | |
90  // | | May have gone past eol with strtok().
91  // | | |
92  if( c == '\n' || c == '\r' || c == 0 )
93  return true;
94 
95  return false;
96 }
97 
98 
108 static bool strCompare( const char* aString, const char* aLine, const char** aOutput = NULL )
109 {
110  size_t len = strlen( aString );
111  bool retv = ( strncasecmp( aLine, aString, len ) == 0 ) &&
112  ( isspace( aLine[ len ] ) || aLine[ len ] == 0 );
113 
114  if( retv && aOutput )
115  {
116  const char* tmp = aLine;
117 
118  // Move past the end of the token.
119  tmp += len;
120 
121  // Move to the beginning of the next token.
122  while( *tmp && isspace( *tmp ) )
123  tmp++;
124 
125  *aOutput = tmp;
126  }
127 
128  return retv;
129 }
130 
131 
145 static int parseInt( FILE_LINE_READER& aReader, const char* aLine, const char** aOutput = NULL )
146 {
147  if( !*aLine )
148  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
149 
150  // Clear errno before calling strtol() in case some other crt call set it.
151  errno = 0;
152 
153  long retv = strtol( aLine, (char**) aOutput, 10 );
154 
155  // Make sure no error occurred when calling strtol().
156  if( errno == ERANGE )
157  SCH_PARSE_ERROR( "invalid integer value", aReader, aLine );
158 
159  // strtol does not strip off whitespace before the next token.
160  if( aOutput )
161  {
162  const char* next = *aOutput;
163 
164  while( *next && isspace( *next ) )
165  next++;
166 
167  *aOutput = next;
168  }
169 
170  return (int) retv;
171 }
172 
173 
187 static unsigned long parseHex( FILE_LINE_READER& aReader, const char* aLine,
188  const char** aOutput = NULL )
189 {
190  if( !*aLine )
191  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
192 
193  unsigned long retv;
194 
195  // Clear errno before calling strtoul() in case some other crt call set it.
196  errno = 0;
197  retv = strtoul( aLine, (char**) aOutput, 16 );
198 
199  // Make sure no error occurred when calling strtoul().
200  if( errno == ERANGE )
201  SCH_PARSE_ERROR( "invalid hexadecimal number", aReader, aLine );
202 
203  // Strip off whitespace before the next token.
204  if( aOutput )
205  {
206  // const char* next = aLine + strlen( token );
207 
208  const char* next = *aOutput;
209 
210  while( *next && isspace( *next ) )
211  next++;
212 
213  *aOutput = next;
214  }
215 
216  return retv;
217 }
218 
219 
233 static double parseDouble( FILE_LINE_READER& aReader, const char* aLine,
234  const char** aOutput = NULL )
235 {
236  if( !*aLine )
237  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
238 
239  // Clear errno before calling strtod() in case some other crt call set it.
240  errno = 0;
241 
242  double retv = strtod( aLine, (char**) aOutput );
243 
244  // Make sure no error occurred when calling strtod().
245  if( errno == ERANGE )
246  SCH_PARSE_ERROR( "invalid floating point number", aReader, aLine );
247 
248  // strtod does not strip off whitespace before the next token.
249  if( aOutput )
250  {
251  const char* next = *aOutput;
252 
253  while( *next && isspace( *next ) )
254  next++;
255 
256  *aOutput = next;
257  }
258 
259  return retv;
260 }
261 
262 
274 static char parseChar( FILE_LINE_READER& aReader, const char* aCurrentToken,
275  const char** aNextToken = NULL )
276 {
277  while( *aCurrentToken && isspace( *aCurrentToken ) )
278  aCurrentToken++;
279 
280  if( !*aCurrentToken )
281  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
282 
283  if( !isspace( *( aCurrentToken + 1 ) ) )
284  SCH_PARSE_ERROR( "expected single character token", aReader, aCurrentToken );
285 
286  if( aNextToken )
287  {
288  const char* next = aCurrentToken + 2;
289 
290  while( *next && isspace( *next ) )
291  next++;
292 
293  *aNextToken = next;
294  }
295 
296  return *aCurrentToken;
297 }
298 
299 
314 static void parseUnquotedString( wxString& aString, FILE_LINE_READER& aReader,
315  const char* aCurrentToken, const char** aNextToken = NULL,
316  bool aCanBeEmpty = false )
317 {
318  if( !*aCurrentToken )
319  {
320  if( aCanBeEmpty )
321  return;
322  else
323  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
324  }
325 
326  const char* tmp = aCurrentToken;
327 
328  while( *tmp && isspace( *tmp ) )
329  tmp++;
330 
331  if( !*tmp )
332  {
333  if( aCanBeEmpty )
334  return;
335  else
336  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
337  }
338 
339  std::string utf8;
340 
341  while( *tmp && !isspace( *tmp ) )
342  utf8 += *tmp++;
343 
344  aString = FROM_UTF8( utf8.c_str() );
345 
346  if( aString.IsEmpty() && !aCanBeEmpty )
347  SCH_PARSE_ERROR( _( "expected unquoted string" ), aReader, aCurrentToken );
348 
349  if( aNextToken )
350  {
351  const char* next = tmp;
352 
353  while( *next && isspace( *next ) )
354  next++;
355 
356  *aNextToken = next;
357  }
358 }
359 
360 
376 static void parseQuotedString( wxString& aString, FILE_LINE_READER& aReader,
377  const char* aCurrentToken, const char** aNextToken = NULL,
378  bool aCanBeEmpty = false )
379 {
380  if( !*aCurrentToken )
381  {
382  if( aCanBeEmpty )
383  return;
384  else
385  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
386  }
387 
388  const char* tmp = aCurrentToken;
389 
390  while( *tmp && isspace( *tmp ) )
391  tmp++;
392 
393  if( !*tmp )
394  {
395  if( aCanBeEmpty )
396  return;
397  else
398  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
399  }
400 
401  // Verify opening quote.
402  if( *tmp != '"' )
403  SCH_PARSE_ERROR( "expecting opening quote", aReader, aCurrentToken );
404 
405  tmp++;
406 
407  std::string utf8; // utf8 without escapes and quotes.
408 
409  // Fetch everything up to closing quote.
410  while( *tmp )
411  {
412  if( *tmp == '\\' )
413  {
414  tmp++;
415 
416  if( !*tmp )
417  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
418 
419  // Do not copy the escape byte if it is followed by \ or "
420  if( *tmp != '"' && *tmp != '\\' )
421  utf8 += '\\';
422 
423  utf8 += *tmp;
424  }
425  else if( *tmp == '"' ) // Closing double quote.
426  {
427  break;
428  }
429  else
430  {
431  utf8 += *tmp;
432  }
433 
434  tmp++;
435  }
436 
437  aString = FROM_UTF8( utf8.c_str() );
438 
439  if( aString.IsEmpty() && !aCanBeEmpty )
440  SCH_PARSE_ERROR( "expected quoted string", aReader, aCurrentToken );
441 
442  if( *tmp && *tmp != '"' )
443  SCH_PARSE_ERROR( "no closing quote for string found", aReader, tmp );
444 
445  // Move past the closing quote.
446  tmp++;
447 
448  if( aNextToken )
449  {
450  const char* next = tmp;
451 
452  while( *next && *next == ' ' )
453  next++;
454 
455  *aNextToken = next;
456  }
457 }
458 
459 
466 {
467  static int m_modHash; // Keep track of the modification status of the library.
468 
469  wxString m_fileName; // Absolute path and file name.
470  wxFileName m_libFileName; // Absolute path and file name is required here.
471  wxDateTime m_fileModTime;
472  LIB_ALIAS_MAP m_aliases; // Map of names of LIB_ALIAS pointers.
477  int m_libType; // Is this cache a component or symbol library.
478 
479  LIB_PART* loadPart( FILE_LINE_READER& aReader );
480  void loadHeader( FILE_LINE_READER& aReader );
481  void loadAliases( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
482  void loadField( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
483  void loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
484  FILE_LINE_READER& aReader );
485  void loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
486  FILE_LINE_READER& aReader );
487  void loadDocs();
488  LIB_ARC* loadArc( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
489  LIB_CIRCLE* loadCircle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
490  LIB_TEXT* loadText( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
491  LIB_RECTANGLE* loadRectangle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
492  LIB_PIN* loadPin( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
493  LIB_POLYLINE* loadPolyLine( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
494  LIB_BEZIER* loadBezier( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
495 
496  FILL_T parseFillMode( FILE_LINE_READER& aReader, const char* aLine,
497  const char** aOutput );
498  bool checkForDuplicates( wxString& aAliasName );
499  LIB_ALIAS* removeAlias( LIB_ALIAS* aAlias );
500 
501  void saveDocFile();
502  void saveSymbol( LIB_PART* aSymbol,
503  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
504  void saveArc( LIB_ARC* aArc, std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
505  void saveBezier( LIB_BEZIER* aBezier,
506  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
507  void saveCircle( LIB_CIRCLE* aCircle,
508  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
509  void saveField( LIB_FIELD* aField,
510  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
511  void savePin( LIB_PIN* aPin, std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
512  void savePolyLine( LIB_POLYLINE* aPolyLine,
513  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
514  void saveRectangle( LIB_RECTANGLE* aRectangle,
515  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
516  void saveText( LIB_TEXT* aText,
517  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
518 
520 
521 public:
522  SCH_LEGACY_PLUGIN_CACHE( const wxString& aLibraryPath );
524 
525  int GetModifyHash() const { return m_modHash; }
526 
527  // Most all functions in this class throw IO_ERROR exceptions. There are no
528  // error codes nor user interface calls from here, nor in any SCH_PLUGIN objects.
529  // Catch these exceptions higher up please.
530 
532  void Save( bool aSaveDocFile = true );
533 
534  void Load();
535 
536  void AddSymbol( const LIB_PART* aPart );
537 
538  void DeleteAlias( const wxString& aAliasName );
539 
540  void DeleteSymbol( const wxString& aAliasName );
541 
542  // If m_libFileName is a symlink follow it to the real source file
543  wxFileName GetRealFile() const;
544 
545  wxDateTime GetLibModificationTime();
546 
547  bool IsFile( const wxString& aFullPathAndFileName ) const;
548 
549  bool IsFileChanged() const;
550 
551  void SetModified( bool aModified = true ) { m_isModified = aModified; }
552 
553  wxString GetLogicalName() const { return m_libFileName.GetName(); }
554 
555  void SetFileName( const wxString& aFileName ) { m_libFileName = aFileName; }
556 
557  wxString GetFileName() const { return m_libFileName.GetFullPath(); }
558 };
559 
560 
562 {
563  init( NULL );
564 }
565 
566 
568 {
569  delete m_cache;
570 }
571 
572 
573 void SCH_LEGACY_PLUGIN::init( KIWAY* aKiway, const PROPERTIES* aProperties )
574 {
575  m_version = 0;
576  m_rootSheet = NULL;
577  m_props = aProperties;
578  m_kiway = aKiway;
579  m_cache = NULL;
580  m_out = NULL;
581 }
582 
583 
584 SCH_SHEET* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway,
585  SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
586 {
587  wxASSERT( !aFileName || aKiway != NULL );
588 
589  LOCALE_IO toggle; // toggles on, then off, the C locale.
590  SCH_SHEET* sheet;
591 
592  wxFileName fn = aFileName;
593 
594  // Unfortunately child sheet file names the legacy schematic file format are not fully
595  // qualified and are always appended to the project path. The aFileName attribute must
596  // always be an absolute path so the project path can be used for load child sheet files.
597  wxASSERT( fn.IsAbsolute() );
598 
599  if( aAppendToMe )
600  {
601  wxLogTrace( traceSchLegacyPlugin, "Append \"%s\" to sheet \"%s\".",
602  aFileName, aAppendToMe->GetFileName() );
603 
604  wxFileName normedFn = aAppendToMe->GetFileName();
605 
606  if( !normedFn.IsAbsolute() )
607  {
608  if( aFileName.Right( normedFn.GetFullPath().Length() ) == normedFn.GetFullPath() )
609  m_path = aFileName.Left( aFileName.Length() - normedFn.GetFullPath().Length() );
610  }
611 
612  if( m_path.IsEmpty() )
613  m_path = aKiway->Prj().GetProjectPath();
614 
615  wxLogTrace( traceSchLegacyPlugin, "Normalized append path \"%s\".", m_path );
616  }
617  else
618  {
619  m_path = aKiway->Prj().GetProjectPath();
620  }
621 
622  m_currentPath.push( m_path );
623  init( aKiway, aProperties );
624 
625  if( aAppendToMe == NULL )
626  {
627  // Clean up any allocated memory if an exception occurs loading the schematic.
628  std::unique_ptr< SCH_SHEET > newSheet( new SCH_SHEET );
629  newSheet->SetFileName( aFileName );
630  m_rootSheet = newSheet.get();
631  loadHierarchy( newSheet.get() );
632 
633  // If we got here, the schematic loaded successfully.
634  sheet = newSheet.release();
635  }
636  else
637  {
638  m_rootSheet = aAppendToMe->GetRootSheet();
639  wxASSERT( m_rootSheet != NULL );
640  sheet = aAppendToMe;
641  loadHierarchy( sheet );
642  }
643 
644  wxASSERT( m_currentPath.size() == 1 ); // only the project path should remain
645 
646  return sheet;
647 }
648 
649 
650 // Everything below this comment is recursive. Modify with care.
651 
653 {
654  SCH_SCREEN* screen = NULL;
655 
656  if( !aSheet->GetScreen() )
657  {
658  // SCH_SCREEN objects store the full path and file name where the SCH_SHEET object only
659  // stores the file name and extension. Add the project path to the file name and
660  // extension to compare when calling SCH_SHEET::SearchHierarchy().
661  wxFileName fileName = aSheet->GetFileName();
662 
663  if( !fileName.IsAbsolute() )
664  fileName.MakeAbsolute( m_currentPath.top() );
665 
666  // Save the current path so that it gets restored when decending and ascending the
667  // sheet hierarchy which allows for sheet schematic files to be nested in folders
668  // relative to the last path a schematic was loaded from.
669  wxLogTrace( traceSchLegacyPlugin, "Saving path \"%s\"", m_currentPath.top() );
670  m_currentPath.push( fileName.GetPath() );
671  wxLogTrace( traceSchLegacyPlugin, "Current path \"%s\"", m_currentPath.top() );
672  wxLogTrace( traceSchLegacyPlugin, "Loading \"%s\"", fileName.GetFullPath() );
673 
674  m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
675 
676  if( screen )
677  {
678  aSheet->SetScreen( screen );
679 
680  // Do not need to load the sub-sheets - this has already been done.
681  }
682  else
683  {
684  aSheet->SetScreen( new SCH_SCREEN( m_kiway ) );
685  aSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
686 
687  try
688  {
689  loadFile( fileName.GetFullPath(), aSheet->GetScreen() );
690 
691  EDA_ITEM* item = aSheet->GetScreen()->GetDrawItems();
692 
693  while( item )
694  {
695  if( item->Type() == SCH_SHEET_T )
696  {
697  SCH_SHEET* sheet = (SCH_SHEET*) item;
698 
699  // Set the parent to aSheet. This effectively creates a method to find
700  // the root sheet from any sheet so a pointer to the root sheet does not
701  // need to be stored globally. Note: this is not the same as a hierarchy.
702  // Complex hierarchies can have multiple copies of a sheet. This only
703  // provides a simple tree to find the root sheet.
704  sheet->SetParent( aSheet );
705 
706  // Recursion starts here.
707  loadHierarchy( sheet );
708  }
709 
710  item = item->Next();
711  }
712  }
713  catch( const IO_ERROR& ioe )
714  {
715  // If there is a problem loading the root sheet, there is no recovery.
716  if( aSheet == m_rootSheet )
717  throw( ioe );
718 
719  // For all subsheets, queue up the error message for the caller.
720  if( !m_error.IsEmpty() )
721  m_error += "\n";
722 
723  m_error += ioe.What();
724  }
725  }
726 
727  m_currentPath.pop();
728  wxLogTrace( traceSchLegacyPlugin, "Restoring path \"%s\"", m_currentPath.top() );
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  // and not always in version 2 for HLabels and GLabels
1372  if( m_version > 1 )
1373  {
1374  if( m_version > 2 || *line >= ' ' )
1375  {
1376  if( strCompare( "Italic", line, &line ) )
1377  text->SetItalic( true );
1378  else if( !strCompare( "~", line, &line ) )
1379  SCH_PARSE_ERROR( _( "expected 'Italics' or '~'" ), aReader, line );
1380  }
1381 
1382  // The thickness token does not exist in older versions of the schematic file format
1383  // so calling parseInt will be made only if the EOL is not reached.
1384  if( *line >= ' ' )
1385  thickness = parseInt( aReader, line, &line );
1386  }
1387 
1388  text->SetBold( thickness != 0 );
1389  text->SetThickness( thickness != 0 ? GetPenSizeForBold( size ) : 0 );
1390 
1391  // Read the text string for the text.
1392  char* tmp = aReader.ReadLine();
1393 
1394  tmp = strtok( tmp, "\r\n" );
1395  wxString val = FROM_UTF8( tmp );
1396 
1397  for( ; ; )
1398  {
1399  int i = val.find( wxT( "\\n" ) );
1400 
1401  if( i == wxNOT_FOUND )
1402  break;
1403 
1404  val.erase( i, 2 );
1405  val.insert( i, wxT( "\n" ) );
1406  }
1407 
1408  text->SetText( val );
1409 
1410  return text.release();
1411 }
1412 
1413 
1415 {
1416  const char* line = aReader.Line();
1417 
1418  wxCHECK( strCompare( "$Comp", line, &line ), NULL );
1419 
1420  std::unique_ptr< SCH_COMPONENT > component( new SCH_COMPONENT() );
1421 
1422  line = aReader.ReadLine();
1423 
1424  while( line != NULL )
1425  {
1426  if( strCompare( "L", line, &line ) )
1427  {
1428  wxString libName;
1429 
1430  parseUnquotedString( libName, aReader, line, &line );
1431  libName.Replace( "~", " " );
1432 
1433  LIB_ID libId;
1434 
1435  // Prior to schematic version 4, library IDs did not have a library nickname so
1436  // parsing the symbol name with LIB_ID::Parse() would break symbol library links
1437  // that contained '/' and ':' characters.
1438  if( m_version > 3 )
1439  libId.Parse( libName, LIB_ID::ID_SCH, true );
1440  else
1441  libId.SetLibItemName( libName, false );
1442 
1443  component->SetLibId( libId );
1444 
1445  wxString refDesignator;
1446 
1447  parseUnquotedString( refDesignator, aReader, line, &line );
1448  refDesignator.Replace( "~", " " );
1449 
1450  wxString prefix = refDesignator;
1451 
1452  while( prefix.Length() )
1453  {
1454  if( ( prefix.Last() < '0' || prefix.Last() > '9') && prefix.Last() != '?' )
1455  break;
1456 
1457  prefix.RemoveLast();
1458  }
1459 
1460  // Avoid a prefix containing trailing/leading spaces
1461  prefix.Trim( true );
1462  prefix.Trim( false );
1463 
1464  if( prefix.IsEmpty() )
1465  component->SetPrefix( wxString( "U" ) );
1466  else
1467  component->SetPrefix( prefix );
1468  }
1469  else if( strCompare( "U", line, &line ) )
1470  {
1471  // This fixes a potentially buggy files caused by unit being set to zero which
1472  // causes netlist issues. See https://bugs.launchpad.net/kicad/+bug/1677282.
1473  int unit = parseInt( aReader, line, &line );
1474 
1475  if( unit == 0 )
1476  {
1477  unit = 1;
1478 
1479  // Set the file as modified so the user can be warned.
1480  if( m_rootSheet && m_rootSheet->GetScreen() )
1481  m_rootSheet->GetScreen()->SetModify();
1482  }
1483 
1484  component->SetUnit( unit );
1485  component->SetConvert( parseInt( aReader, line, &line ) );
1486  component->SetTimeStamp( parseHex( aReader, line, &line ) );
1487  }
1488  else if( strCompare( "P", line, &line ) )
1489  {
1490  wxPoint pos;
1491 
1492  pos.x = parseInt( aReader, line, &line );
1493  pos.y = parseInt( aReader, line, &line );
1494  component->SetPosition( pos );
1495  }
1496  else if( strCompare( "AR", line, &line ) )
1497  {
1498  const char* strCompare = "Path=";
1499  int len = strlen( strCompare );
1500 
1501  if( strncasecmp( strCompare, line, len ) != 0 )
1502  SCH_PARSE_ERROR( "missing 'Path=' token", aReader, line );
1503 
1504  line += len;
1505  wxString path, reference, unit;
1506 
1507  parseQuotedString( path, aReader, line, &line );
1508 
1509  strCompare = "Ref=";
1510  len = strlen( strCompare );
1511 
1512  if( strncasecmp( strCompare, line, len ) != 0 )
1513  SCH_PARSE_ERROR( "missing 'Ref=' token", aReader, line );
1514 
1515  line+= len;
1516  parseQuotedString( reference, aReader, line, &line );
1517 
1518  strCompare = "Part=";
1519  len = strlen( strCompare );
1520 
1521  if( strncasecmp( strCompare, line, len ) != 0 )
1522  SCH_PARSE_ERROR( "missing 'Part=' token", aReader, line );
1523 
1524  line+= len;
1525  parseQuotedString( unit, aReader, line, &line );
1526 
1527  long tmp;
1528 
1529  if( !unit.ToLong( &tmp, 10 ) )
1530  SCH_PARSE_ERROR( "expected integer value", aReader, line );
1531 
1532  if( tmp < 0 || tmp > MAX_UNIT_COUNT_PER_PACKAGE )
1533  SCH_PARSE_ERROR( "unit value out of range", aReader, line );
1534 
1535  component->AddHierarchicalReference( path, reference, (int)tmp );
1536  component->GetField( REFERENCE )->SetText( reference );
1537 
1538  }
1539  else if( strCompare( "F", line, &line ) )
1540  {
1541  int index = parseInt( aReader, line, &line );
1542 
1543  wxString text, name;
1544 
1545  parseQuotedString( text, aReader, line, &line, true );
1546 
1547  char orientation = parseChar( aReader, line, &line );
1548  wxPoint pos;
1549  pos.x = parseInt( aReader, line, &line );
1550  pos.y = parseInt( aReader, line, &line );
1551  int size = parseInt( aReader, line, &line );
1552  int attributes = parseHex( aReader, line, &line );
1553 
1554  if( index >= component->GetFieldCount() )
1555  {
1556  // The first MANDATOR_FIELDS _must_ be constructed within
1557  // the SCH_COMPONENT constructor. This assert is simply here
1558  // to guard against a change in that constructor.
1559  wxASSERT( component->GetFieldCount() >= MANDATORY_FIELDS );
1560 
1561  // Ignore the _supplied_ fieldNdx. It is not important anymore
1562  // if within the user defined fields region (i.e. >= MANDATORY_FIELDS).
1563  // We freely renumber the index to fit the next available field slot.
1564  index = component->GetFieldCount(); // new has this index after insertion
1565 
1566  SCH_FIELD field( wxPoint( 0, 0 ), -1, component.get(), name );
1567  component->AddField( field );
1568  }
1569 
1570  // Prior to version 2 of the schematic file format, none of the following existed.
1571  if( m_version > 1 )
1572  {
1573  wxString textAttrs;
1574  char hjustify = parseChar( aReader, line, &line );
1575 
1576  parseUnquotedString( textAttrs, aReader, line, &line );
1577 
1578  // The name of the field is optional.
1579  parseQuotedString( name, aReader, line, &line, true );
1580 
1581  if( hjustify == 'L' )
1582  component->GetField( index )->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
1583  else if( hjustify == 'R' )
1584  component->GetField( index )->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
1585  else if( hjustify != 'C' )
1586  SCH_PARSE_ERROR( "component field text horizontal justification must be "
1587  "L, R, or C", aReader, line );
1588 
1589  // We are guaranteed to have a least one character here for older file formats
1590  // otherwise an exception would have been raised..
1591  if( textAttrs[0] == 'T' )
1592  component->GetField( index )->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
1593  else if( textAttrs[0] == 'B' )
1594  component->GetField( index )->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
1595  else if( textAttrs[0] != 'C' )
1596  SCH_PARSE_ERROR( "component field text vertical justification must be "
1597  "B, T, or C", aReader, line );
1598 
1599  // Newer file formats include the bold and italics text attribute.
1600  if( textAttrs.Length() > 1 )
1601  {
1602  if( textAttrs.Length() != 3 )
1603  SCH_PARSE_ERROR( _( "component field text attributes must be 3 characters wide" ),
1604  aReader, line );
1605 
1606  if( textAttrs[1] == 'I' )
1607  component->GetField( index )->SetItalic( true );
1608  else if( textAttrs[1] != 'N' )
1609  SCH_PARSE_ERROR( "component field text italics indicator must be I or N",
1610  aReader, line );
1611 
1612  if( textAttrs[2] == 'B' )
1613  component->GetField( index )->SetBold( true );
1614  else if( textAttrs[2] != 'N' )
1615  SCH_PARSE_ERROR( "component field text bold indicator must be B or N",
1616  aReader, line );
1617  }
1618  }
1619 
1620  component->GetField( index )->SetText( text );
1621  component->GetField( index )->SetTextPos( pos );
1622  component->GetField( index )->SetVisible( !attributes );
1623  component->GetField( index )->SetTextSize( wxSize( size, size ) );
1624 
1625  if( orientation == 'H' )
1626  component->GetField( index )->SetTextAngle( TEXT_ANGLE_HORIZ );
1627  else if( orientation == 'V' )
1628  component->GetField( index )->SetTextAngle( TEXT_ANGLE_VERT );
1629  else
1630  SCH_PARSE_ERROR( "component field orientation must be H or V",
1631  aReader, line );
1632 
1633  if( name.IsEmpty() )
1635 
1636  component->GetField( index )->SetName( name );
1637  }
1638  else if( strCompare( "$EndComp", line ) )
1639  {
1640  // Ensure all flags (some are set by previous initializations) are reset:
1641  component->ClearFlags();
1642  return component.release();
1643  }
1644  else
1645  {
1646  // There are two lines that begin with a tab or spaces that includes a line with the
1647  // redundant position information and the transform matrix settings.
1648 
1649  // Parse the redundant position information just the same to check for formatting
1650  // errors.
1651  parseInt( aReader, line, &line ); // Always 1.
1652  parseInt( aReader, line, &line ); // The X coordinate.
1653  parseInt( aReader, line, &line ); // The Y coordinate.
1654 
1655  line = aReader.ReadLine();
1656 
1657  TRANSFORM transform;
1658 
1659  transform.x1 = parseInt( aReader, line, &line );
1660 
1661  if( transform.x1 < -1 || transform.x1 > 1 )
1662  SCH_PARSE_ERROR( "invalid component X1 transform value", aReader, line );
1663 
1664  transform.y1 = parseInt( aReader, line, &line );
1665 
1666  if( transform.y1 < -1 || transform.y1 > 1 )
1667  SCH_PARSE_ERROR( "invalid component Y1 transform value", aReader, line );
1668 
1669  transform.x2 = parseInt( aReader, line, &line );
1670 
1671  if( transform.x2 < -1 || transform.x2 > 1 )
1672  SCH_PARSE_ERROR( "invalid component X2 transform value", aReader, line );
1673 
1674  transform.y2 = parseInt( aReader, line, &line );
1675 
1676  if( transform.y2 < -1 || transform.y2 > 1 )
1677  SCH_PARSE_ERROR( "invalid component Y2 transform value", aReader, line );
1678 
1679  component->SetTransform( transform );
1680  }
1681 
1682  line = aReader.ReadLine();
1683  }
1684 
1685  SCH_PARSE_ERROR( "invalid component line", aReader, line );
1686 
1687  return NULL; // Prevents compiler warning. Should never get here.
1688 }
1689 
1690 
1691 void SCH_LEGACY_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aScreen, KIWAY* aKiway,
1692  const PROPERTIES* aProperties )
1693 {
1694  wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN object." );
1695  wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
1696 
1697  LOCALE_IO toggle; // toggles on, then off, the C locale, to write floating point values.
1698 
1699  init( aKiway, aProperties );
1700 
1701  wxFileName fn = aFileName;
1702 
1703  // File names should be absolute. Don't assume everything relative to the project path
1704  // works properly.
1705  wxASSERT( fn.IsAbsolute() );
1706 
1707  FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
1708 
1709  m_out = &formatter; // no ownership
1710 
1711  Format( aScreen );
1712 }
1713 
1714 
1716 {
1717  wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN* object." );
1718  wxCHECK_RET( m_kiway != NULL, "NULL KIWAY* object." );
1719 
1720  // Write the header
1721  m_out->Print( 0, "%s %s %d\n", "EESchema", SCHEMATIC_HEAD_STRING, EESCHEMA_VERSION );
1722 
1723  // Write the project libraries.
1724  for( const PART_LIB& lib : *m_kiway->Prj().SchLibs() )
1725  m_out->Print( 0, "LIBS:%s\n", TO_UTF8( lib.GetName() ) );
1726 
1727  // This section is not used, but written for file compatibility
1728  m_out->Print( 0, "EELAYER %d %d\n", SCH_LAYER_ID_COUNT, 0 );
1729  m_out->Print( 0, "EELAYER END\n" );
1730 
1731  /* Write page info, ScreenNumber and NumberOfScreen; not very meaningful for
1732  * SheetNumber and Sheet Count in a complex hierarchy, but useful in
1733  * simple hierarchy and flat hierarchy. Used also to search the root
1734  * sheet ( ScreenNumber = 1 ) within the files
1735  */
1736  const TITLE_BLOCK& tb = aScreen->GetTitleBlock();
1737  const PAGE_INFO& page = aScreen->GetPageSettings();
1738 
1739  m_out->Print( 0, "$Descr %s %d %d%s\n", TO_UTF8( page.GetType() ),
1740  page.GetWidthMils(),
1741  page.GetHeightMils(),
1742  !page.IsCustom() && page.IsPortrait() ? " portrait" : "" );
1743  m_out->Print( 0, "encoding utf-8\n" );
1744  m_out->Print( 0, "Sheet %d %d\n", aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens );
1745  m_out->Print( 0, "Title %s\n", EscapedUTF8( tb.GetTitle() ).c_str() );
1746  m_out->Print( 0, "Date %s\n", EscapedUTF8( tb.GetDate() ).c_str() );
1747  m_out->Print( 0, "Rev %s\n", EscapedUTF8( tb.GetRevision() ).c_str() );
1748  m_out->Print( 0, "Comp %s\n", EscapedUTF8( tb.GetCompany() ).c_str() );
1749  m_out->Print( 0, "Comment1 %s\n", EscapedUTF8( tb.GetComment1() ).c_str() );
1750  m_out->Print( 0, "Comment2 %s\n", EscapedUTF8( tb.GetComment2() ).c_str() );
1751  m_out->Print( 0, "Comment3 %s\n", EscapedUTF8( tb.GetComment3() ).c_str() );
1752  m_out->Print( 0, "Comment4 %s\n", EscapedUTF8( tb.GetComment4() ).c_str() );
1753  m_out->Print( 0, "$EndDescr\n" );
1754 
1755  for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
1756  {
1757  switch( item->Type() )
1758  {
1759  case SCH_COMPONENT_T:
1760  saveComponent( static_cast< SCH_COMPONENT* >( item ) );
1761  break;
1762  case SCH_BITMAP_T:
1763  saveBitmap( static_cast< SCH_BITMAP* >( item ) );
1764  break;
1765  case SCH_SHEET_T:
1766  saveSheet( static_cast< SCH_SHEET* >( item ) );
1767  break;
1768  case SCH_JUNCTION_T:
1769  saveJunction( static_cast< SCH_JUNCTION* >( item ) );
1770  break;
1771  case SCH_NO_CONNECT_T:
1772  saveNoConnect( static_cast< SCH_NO_CONNECT* >( item ) );
1773  break;
1774  case SCH_BUS_WIRE_ENTRY_T:
1775  case SCH_BUS_BUS_ENTRY_T:
1776  saveBusEntry( static_cast< SCH_BUS_ENTRY_BASE* >( item ) );
1777  break;
1778  case SCH_LINE_T:
1779  saveLine( static_cast< SCH_LINE* >( item ) );
1780  break;
1781  case SCH_TEXT_T:
1782  case SCH_LABEL_T:
1783  case SCH_GLOBAL_LABEL_T:
1785  saveText( static_cast< SCH_TEXT* >( item ) );
1786  break;
1787  default:
1788  wxASSERT( "Unexpected schematic object type in SCH_LEGACY_PLUGIN::Format()" );
1789  }
1790  }
1791 
1792  m_out->Print( 0, "$EndSCHEMATC\n" );
1793 }
1794 
1795 
1797 {
1798  std::string name1;
1799  std::string name2;
1800  wxArrayString reference_fields;
1801 
1802  static wxString delimiters( wxT( " " ) );
1803 
1804  // This is redundant with the AR entries below, but it makes the files backwards-compatible.
1805  if( aComponent->GetPathsAndReferences().GetCount() > 0 )
1806  {
1807  reference_fields = wxStringTokenize( aComponent->GetPathsAndReferences()[0], delimiters );
1808  name1 = toUTFTildaText( reference_fields[1] );
1809  }
1810  else
1811  {
1812  if( aComponent->GetField( REFERENCE )->GetText().IsEmpty() )
1813  name1 = toUTFTildaText( aComponent->GetPrefix() );
1814  else
1815  name1 = toUTFTildaText( aComponent->GetField( REFERENCE )->GetText() );
1816  }
1817 
1818  wxString part_name = aComponent->GetLibId().Format();
1819 
1820  if( part_name.size() )
1821  {
1822  name2 = toUTFTildaText( part_name );
1823  }
1824  else
1825  {
1826  name2 = "_NONAME_";
1827  }
1828 
1829  m_out->Print( 0, "$Comp\n" );
1830  m_out->Print( 0, "L %s %s\n", name2.c_str(), name1.c_str() );
1831 
1832  // Generate unit number, convert and time stamp
1833  m_out->Print( 0, "U %d %d %8.8lX\n", aComponent->GetUnit(), aComponent->GetConvert(),
1834  (unsigned long)aComponent->GetTimeStamp() );
1835 
1836  // Save the position
1837  m_out->Print( 0, "P %d %d\n", aComponent->GetPosition().x, aComponent->GetPosition().y );
1838 
1839  /* If this is a complex hierarchy; save hierarchical references.
1840  * but for simple hierarchies it is not necessary.
1841  * the reference inf is already saved
1842  * this is useful for old Eeschema version compatibility
1843  */
1844  if( aComponent->GetPathsAndReferences().GetCount() > 1 )
1845  {
1846  for( unsigned int ii = 0; ii < aComponent->GetPathsAndReferences().GetCount(); ii++ )
1847  {
1848  /*format:
1849  * AR Path="/140/2" Ref="C99" Part="1"
1850  * where 140 is the uid of the containing sheet
1851  * and 2 is the timestamp of this component.
1852  * (timestamps are actually 8 hex chars)
1853  * Ref is the conventional component reference for this 'path'
1854  * Part is the conventional component part selection for this 'path'
1855  */
1856  reference_fields = wxStringTokenize( aComponent->GetPathsAndReferences()[ii],
1857  delimiters );
1858 
1859  m_out->Print( 0, "AR Path=\"%s\" Ref=\"%s\" Part=\"%s\" \n",
1860  TO_UTF8( reference_fields[0] ),
1861  TO_UTF8( reference_fields[1] ),
1862  TO_UTF8( reference_fields[2] ) );
1863  }
1864  }
1865 
1866  // update the ugly field index, which I would like to see go away someday soon.
1867  for( int i = 0; i < aComponent->GetFieldCount(); ++i )
1868  aComponent->GetField( i )->SetId( i );
1869 
1870  // Fixed fields:
1871  // Save mandatory fields even if they are blank,
1872  // because the visibility, size and orientation are set from libary editor.
1873  for( unsigned i = 0; i < MANDATORY_FIELDS; ++i )
1874  saveField( aComponent->GetField( i ) );
1875 
1876  // User defined fields:
1877  // The *policy* about which user defined fields are part of a symbol is now
1878  // only in the dialog editors. No policy should be enforced here, simply
1879  // save all the user defined fields, they are present because a dialog editor
1880  // thought they should be. If you disagree, go fix the dialog editors.
1881  for( int i = MANDATORY_FIELDS; i < aComponent->GetFieldCount(); ++i )
1882  saveField( aComponent->GetField( i ) );
1883 
1884  // Unit number, position, box ( old standard )
1885  m_out->Print( 0, "\t%-4d %-4d %-4d\n", aComponent->GetUnit(), aComponent->GetPosition().x,
1886  aComponent->GetPosition().y );
1887 
1888  TRANSFORM transform = aComponent->GetTransform();
1889 
1890  m_out->Print( 0, "\t%-4d %-4d %-4d %-4d\n",
1891  transform.x1, transform.y1, transform.x2, transform.y2 );
1892  m_out->Print( 0, "$EndComp\n" );
1893 }
1894 
1895 
1897 {
1898  char hjustify = 'C';
1899 
1900  if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
1901  hjustify = 'L';
1902  else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
1903  hjustify = 'R';
1904 
1905  char vjustify = 'C';
1906 
1907  if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
1908  vjustify = 'B';
1909  else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
1910  vjustify = 'T';
1911 
1912  m_out->Print( 0, "F %d %s %c %-3d %-3d %-3d %4.4X %c %c%c%c",
1913  aField->GetId(),
1914  EscapedUTF8( aField->GetText() ).c_str(), // wraps in quotes too
1915  aField->GetTextAngle() == TEXT_ANGLE_HORIZ ? 'H' : 'V',
1916  aField->GetLibPosition().x, aField->GetLibPosition().y,
1917  aField->GetTextWidth(),
1918  !aField->IsVisible(),
1919  hjustify, vjustify,
1920  aField->IsItalic() ? 'I' : 'N',
1921  aField->IsBold() ? 'B' : 'N' );
1922 
1923  // Save field name, if the name is user definable
1924  if( aField->GetId() >= FIELD1 )
1925  {
1926  m_out->Print( 0, " %s", EscapedUTF8( aField->GetName() ).c_str() );
1927  }
1928 
1929  m_out->Print( 0, "\n" );
1930 }
1931 
1932 
1934 {
1935  wxCHECK_RET( aBitmap != NULL, "SCH_BITMAP* is NULL" );
1936 
1937  wxImage* image = aBitmap->GetImage()->GetImageData();
1938 
1939  wxCHECK_RET( image != NULL, "wxImage* is NULL" );
1940 
1941  m_out->Print( 0, "$Bitmap\n" );
1942  m_out->Print( 0, "Pos %-4d %-4d\n", aBitmap->GetPosition().x, aBitmap->GetPosition().y );
1943  m_out->Print( 0, "Scale %f\n", aBitmap->GetImage()->GetScale() );
1944  m_out->Print( 0, "Data\n" );
1945 
1946  wxMemoryOutputStream stream;
1947 
1948  image->SaveFile( stream, wxBITMAP_TYPE_PNG );
1949 
1950  // Write binary data in hexadecimal form (ASCII)
1951  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
1952  char* begin = (char*) buffer->GetBufferStart();
1953 
1954  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
1955  {
1956  if( ii >= 32 )
1957  {
1958  ii = 0;
1959 
1960  m_out->Print( 0, "\n" );
1961  }
1962 
1963  m_out->Print( 0, "%2.2X ", *begin & 0xFF );
1964  }
1965 
1966  m_out->Print( 0, "\nEndData\n" );
1967  m_out->Print( 0, "$EndBitmap\n" );
1968 }
1969 
1970 
1972 {
1973  wxCHECK_RET( aSheet != NULL, "SCH_SHEET* is NULL" );
1974 
1975  m_out->Print( 0, "$Sheet\n" );
1976  m_out->Print( 0, "S %-4d %-4d %-4d %-4d\n",
1977  aSheet->GetPosition().x, aSheet->GetPosition().y,
1978  aSheet->GetSize().x, aSheet->GetSize().y );
1979 
1980  m_out->Print( 0, "U %8.8lX\n", (unsigned long) aSheet->GetTimeStamp() );
1981 
1982  if( !aSheet->GetName().IsEmpty() )
1983  m_out->Print( 0, "F0 %s %d\n", EscapedUTF8( aSheet->GetName() ).c_str(),
1984  aSheet->GetSheetNameSize() );
1985 
1986  if( !aSheet->GetFileName().IsEmpty() )
1987  m_out->Print( 0, "F1 %s %d\n", EscapedUTF8( aSheet->GetFileName() ).c_str(),
1988  aSheet->GetFileNameSize() );
1989 
1990  for( const SCH_SHEET_PIN& pin : aSheet->GetPins() )
1991  {
1992  int type, side;
1993 
1994  if( pin.GetText().IsEmpty() )
1995  break;
1996 
1997  switch( pin.GetEdge() )
1998  {
1999  default:
2001  side = 'L';
2002  break;
2003 
2005  side = 'R';
2006  break;
2007 
2009  side = 'T';
2010  break;
2011 
2013  side = 'B';
2014  break;
2015  }
2016 
2017  switch( pin.GetShape() )
2018  {
2019  case NET_INPUT:
2020  type = 'I'; break;
2021 
2022  case NET_OUTPUT:
2023  type = 'O'; break;
2024 
2025  case NET_BIDI:
2026  type = 'B'; break;
2027 
2028  case NET_TRISTATE:
2029  type = 'T'; break;
2030 
2031  default:
2032  case NET_UNSPECIFIED:
2033  type = 'U'; break;
2034  }
2035 
2036  m_out->Print( 0, "F%d %s %c %c %-3d %-3d %-3d\n", pin.GetNumber(),
2037  EscapedUTF8( pin.GetText() ).c_str(), // supplies wrapping quotes
2038  type, side, pin.GetPosition().x, pin.GetPosition().y,
2039  pin.GetTextWidth() );
2040  }
2041 
2042  m_out->Print( 0, "$EndSheet\n" );
2043 }
2044 
2045 
2047 {
2048  wxCHECK_RET( aJunction != NULL, "SCH_JUNCTION* is NULL" );
2049 
2050  m_out->Print( 0, "Connection ~ %-4d %-4d\n",
2051  aJunction->GetPosition().x, aJunction->GetPosition().y );
2052 }
2053 
2054 
2056 {
2057  wxCHECK_RET( aNoConnect != NULL, "SCH_NOCONNECT* is NULL" );
2058 
2059  m_out->Print( 0, "NoConn ~ %-4d %-4d\n", aNoConnect->GetPosition().x,
2060  aNoConnect->GetPosition().y );
2061 }
2062 
2063 
2065 {
2066  wxCHECK_RET( aBusEntry != NULL, "SCH_BUS_ENTRY_BASE* is NULL" );
2067 
2068  if( aBusEntry->GetLayer() == LAYER_WIRE )
2069  m_out->Print( 0, "Entry Wire Line\n\t%-4d %-4d %-4d %-4d\n",
2070  aBusEntry->GetPosition().x, aBusEntry->GetPosition().y,
2071  aBusEntry->m_End().x, aBusEntry->m_End().y );
2072  else
2073  m_out->Print( 0, "Entry Bus Bus\n\t%-4d %-4d %-4d %-4d\n",
2074  aBusEntry->GetPosition().x, aBusEntry->GetPosition().y,
2075  aBusEntry->m_End().x, aBusEntry->m_End().y );
2076 }
2077 
2078 
2080 {
2081  wxCHECK_RET( aLine != NULL, "SCH_LINE* is NULL" );
2082 
2083  const char* layer = "Notes";
2084  const char* width = "Line";
2085 
2086  if( aLine->GetLayer() == LAYER_WIRE )
2087  layer = "Wire";
2088  else if( aLine->GetLayer() == LAYER_BUS )
2089  layer = "Bus";
2090 
2091  m_out->Print( 0, "Wire %s %s", layer, width );
2092 
2093  // Write line style (width, type, color) only for non default values
2094  if( aLine->GetLayer() == LAYER_NOTES )
2095  {
2096  if( aLine->GetPenSize() != aLine->GetDefaultWidth() )
2097  m_out->Print( 0, " %s %d", T_WIDTH, aLine->GetLineSize() );
2098 
2099  if( aLine->GetLineStyle() != aLine->GetDefaultStyle() )
2100  m_out->Print( 0, " %s %s", T_STYLE, SCH_LINE::GetLineStyleName( aLine->GetLineStyle() ) );
2101 
2102  if( aLine->GetLineColor() != aLine->GetDefaultColor() )
2103  m_out->Print( 0, " %s",
2104  TO_UTF8( aLine->GetLineColor().ToColour().GetAsString( wxC2S_CSS_SYNTAX ) ) );
2105  }
2106 
2107  m_out->Print( 0, "\n" );
2108 
2109  m_out->Print( 0, "\t%-4d %-4d %-4d %-4d",
2110  aLine->GetStartPoint().x, aLine->GetStartPoint().y,
2111  aLine->GetEndPoint().x, aLine->GetEndPoint().y );
2112 
2113  m_out->Print( 0, "\n");
2114 }
2115 
2116 
2118 {
2119  wxCHECK_RET( aText != NULL, "SCH_TEXT* is NULL" );
2120 
2121  const char* italics = "~";
2122  const char* textType = "Notes";
2123 
2124  if( aText->IsItalic() )
2125  italics = "Italic";
2126 
2127  wxString text = aText->GetText();
2128 
2129  SCH_LAYER_ID layer = aText->GetLayer();
2130 
2131  if( layer == LAYER_NOTES || layer == LAYER_LOCLABEL )
2132  {
2133  if( layer == LAYER_NOTES )
2134  {
2135  // For compatibility reasons, the text must be saved in only one text line
2136  // so replace all EOLs with \\n
2137  text.Replace( wxT( "\n" ), wxT( "\\n" ) );
2138 
2139  // Here we should have no CR or LF character in line
2140  // This is not always the case if a multiline text was copied (using a copy/paste
2141  // function) from a text that uses E.O.L characters that differs from the current
2142  // EOL format. This is mainly the case under Linux using LF symbol when copying
2143  // a text from Windows (using CRLF symbol) so we must just remove the extra CR left
2144  // (or LF left under MacOSX)
2145  for( unsigned ii = 0; ii < text.Len(); )
2146  {
2147  if( text[ii] == 0x0A || text[ii] == 0x0D )
2148  text.erase( ii, 1 );
2149  else
2150  ii++;
2151  }
2152  }
2153  else
2154  {
2155  textType = "Label";
2156  }
2157 
2158  m_out->Print( 0, "Text %s %-4d %-4d %-4d %-4d %s %d\n%s\n", textType,
2159  aText->GetPosition().x, aText->GetPosition().y,
2160  aText->GetLabelSpinStyle(),
2161  aText->GetTextWidth(),
2162  italics, aText->GetThickness(), TO_UTF8( text ) );
2163  }
2164  else if( layer == LAYER_GLOBLABEL || layer == LAYER_HIERLABEL )
2165  {
2166  textType = ( layer == LAYER_GLOBLABEL ) ? "GLabel" : "HLabel";
2167 
2168  m_out->Print( 0, "Text %s %-4d %-4d %-4d %-4d %s %s %d\n%s\n", textType,
2169  aText->GetPosition().x, aText->GetPosition().y,
2170  aText->GetLabelSpinStyle(),
2171  aText->GetTextWidth(),
2172  SheetLabelType[aText->GetShape()],
2173  italics,
2174  aText->GetThickness(), TO_UTF8( text ) );
2175  }
2176 }
2177 
2178 
2179 int SCH_LEGACY_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up
2180 
2181 
2182 SCH_LEGACY_PLUGIN_CACHE::SCH_LEGACY_PLUGIN_CACHE( const wxString& aFullPathAndFileName ) :
2183  m_fileName( aFullPathAndFileName ),
2184  m_libFileName( aFullPathAndFileName ),
2185  m_isWritable( true ),
2186  m_isModified( false )
2187 {
2188  m_versionMajor = -1;
2189  m_versionMinor = -1;
2191 }
2192 
2193 
2195 {
2196  // When the cache is destroyed, all of the alias objects on the heap should be deleted.
2197  for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); ++it )
2198  {
2199  wxLogTrace( traceSchLegacyPlugin, wxT( "Removing alias %s from library %s." ),
2200  GetChars( it->second->GetName() ), GetChars( GetLogicalName() ) );
2201  LIB_PART* part = it->second->GetPart();
2202  LIB_ALIAS* alias = it->second;
2203  delete alias;
2204 
2205  // When the last alias of a part is destroyed, the part is no longer required and it
2206  // too is destroyed.
2207  if( part && part->GetAliasCount() == 0 )
2208  delete part;
2209  }
2210 
2211  m_aliases.clear();
2212 }
2213 
2214 
2215 // If m_libFileName is a symlink follow it to the real source file
2217 {
2218  wxFileName fn( m_libFileName );
2219 
2220 #ifndef __WINDOWS__
2221  if( fn.Exists( wxFILE_EXISTS_SYMLINK ) )
2222  {
2223  char buffer[ PATH_MAX + 1 ];
2224  ssize_t pathLen = readlink( TO_UTF8( fn.GetFullPath() ), buffer, PATH_MAX );
2225 
2226  if( pathLen > 0 )
2227  {
2228  buffer[ pathLen ] = '\0';
2229  fn.Assign( fn.GetPath() + wxT( "/" ) + wxString::FromUTF8( buffer ) );
2230  fn.Normalize();
2231  }
2232  }
2233 #endif
2234 
2235  return fn;
2236 }
2237 
2238 
2240 {
2241  wxFileName fn = GetRealFile();
2242 
2243  // update the writable flag while we have a wxFileName, in a network this
2244  // is possibly quite dynamic anyway.
2245  m_isWritable = fn.IsFileWritable();
2246 
2247  return fn.GetModificationTime();
2248 }
2249 
2250 
2251 bool SCH_LEGACY_PLUGIN_CACHE::IsFile( const wxString& aFullPathAndFileName ) const
2252 {
2253  return m_fileName == aFullPathAndFileName;
2254 }
2255 
2256 
2258 {
2259  wxFileName fn = GetRealFile();
2260 
2261  if( m_fileModTime.IsValid() && fn.IsOk() && fn.FileExists() )
2262  return fn.GetModificationTime() != m_fileModTime;
2263 
2264  return false;
2265 }
2266 
2267 
2269 {
2270  wxCHECK_MSG( aAlias != NULL, NULL, "NULL pointer cannot be removed from library." );
2271 
2272  LIB_ALIAS_MAP::iterator it = m_aliases.find( aAlias->GetName() );
2273 
2274  if( it == m_aliases.end() )
2275  return NULL;
2276 
2277  // If the entry pointer doesn't match the name it is mapped to in the library, we
2278  // have done something terribly wrong.
2279  wxCHECK_MSG( *it->second == aAlias, NULL,
2280  "Pointer mismatch while attempting to remove alias entry <" + aAlias->GetName() +
2281  "> from library cache <" + m_libFileName.GetName() + ">." );
2282 
2283  LIB_ALIAS* alias = aAlias;
2284  LIB_PART* part = alias->GetPart();
2285 
2286  alias = part->RemoveAlias( alias );
2287 
2288  if( !alias )
2289  {
2290  delete part;
2291 
2292  if( m_aliases.size() > 1 )
2293  {
2294  LIB_ALIAS_MAP::iterator next = it;
2295  next++;
2296 
2297  if( next == m_aliases.end() )
2298  next = m_aliases.begin();
2299 
2300  alias = next->second;
2301  }
2302  }
2303 
2304  m_aliases.erase( it );
2305  m_isModified = true;
2306  ++m_modHash;
2307  return alias;
2308 }
2309 
2310 
2312 {
2313  // aPart is cloned in PART_LIB::AddPart(). The cache takes ownership of aPart.
2314  wxArrayString aliasNames = aPart->GetAliasNames();
2315 
2316  for( size_t i = 0; i < aliasNames.size(); i++ )
2317  {
2318  LIB_ALIAS_MAP::iterator it = m_aliases.find( aliasNames[i] );
2319 
2320  if( it != m_aliases.end() )
2321  removeAlias( it->second );
2322 
2323  LIB_ALIAS* alias = const_cast< LIB_PART* >( aPart )->GetAlias( aliasNames[i] );
2324 
2325  wxASSERT_MSG( alias != NULL, "No alias <" + aliasNames[i] + "> found in symbol <" +
2326  aPart->GetName() +">." );
2327 
2328  m_aliases[ aliasNames[i] ] = alias;
2329  }
2330 
2331  m_isModified = true;
2332  ++m_modHash;
2333 }
2334 
2335 
2337 {
2338  if( !m_libFileName.FileExists() )
2339  {
2340  wxString msg = wxString::Format( _( "Library file \"%s\" not found.\n\n"
2341  "Use the Manage Symbol Libraries dialog to fix the "
2342  "path (or remove the library)." ),
2343  m_libFileName.GetFullPath() );
2344  KIDIALOG dlg( Pgm().App().GetTopWindow(), msg, KIDIALOG::KD_ERROR );
2345  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2346  dlg.ShowModal();
2347  return;
2348  }
2349 
2350  wxCHECK_RET( m_libFileName.IsAbsolute(),
2351  wxString::Format( "Cannot use relative file paths in legacy plugin to "
2352  "open library \"%s\".", m_libFileName.GetFullPath() ) );
2353 
2354  wxLogTrace( traceSchLegacyPlugin, "Loading legacy symbol file \"%s\"",
2355  m_libFileName.GetFullPath() );
2356 
2357  FILE_LINE_READER reader( m_libFileName.GetFullPath() );
2358 
2359  if( !reader.ReadLine() )
2360  THROW_IO_ERROR( _( "unexpected end of file" ) );
2361 
2362  const char* line = reader.Line();
2363 
2364  if( !strCompare( "EESchema-LIBRARY Version", line, &line ) )
2365  {
2366  // Old .sym files (which are libraries with only one symbol, used to store and reuse shapes)
2367  // EESchema-LIB Version x.x SYMBOL. They are valid files.
2368  if( !strCompare( "EESchema-LIB Version", line, &line ) )
2369  SCH_PARSE_ERROR( "file is not a valid component or symbol library file", reader, line );
2370  }
2371 
2372  m_versionMajor = parseInt( reader, line, &line );
2373 
2374  if( *line != '.' )
2375  SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
2376 
2377  line++;
2378 
2379  m_versionMinor = parseInt( reader, line, &line );
2380 
2381  if( m_versionMajor < 1 || m_versionMinor < 0 || m_versionMinor > 99 )
2382  SCH_PARSE_ERROR( "invalid file version in header", reader, line );
2383 
2384  // Check if this is a symbol library which is the same as a component library but without
2385  // any alias, documentation, footprint filters, etc.
2386  if( strCompare( "SYMBOL", line, &line ) )
2387  {
2388  // Symbol files add date and time stamp info to the header.
2390 
2392  }
2393  else
2394  {
2396  }
2397 
2398  while( reader.ReadLine() )
2399  {
2400  line = reader.Line();
2401 
2402  if( *line == '#' || isspace( *line ) ) // Skip comments and blank lines.
2403  continue;
2404 
2405  // Headers where only supported in older library file formats.
2406  if( m_libType == LIBRARY_TYPE_EESCHEMA && strCompare( "$HEADER", line ) )
2407  loadHeader( reader );
2408 
2409  if( strCompare( "DEF", line ) )
2410  {
2411  // Read one DEF/ENDDEF part entry from library:
2412  loadPart( reader );
2413  }
2414  }
2415 
2416  ++m_modHash;
2417 
2418  // Remember the file modification time of library file when the
2419  // cache snapshot was made, so that in a networked environment we will
2420  // reload the cache as needed.
2422 
2424  loadDocs();
2425 }
2426 
2427 
2429 {
2430  const char* line;
2431  wxString text;
2432  wxString aliasName;
2433  wxFileName fn = m_libFileName;
2434  LIB_ALIAS* alias = NULL;;
2435 
2436  fn.SetExt( DOC_EXT );
2437 
2438  // Not all libraries will have a document file.
2439  if( !fn.FileExists() )
2440  return;
2441 
2442  if( !fn.IsFileReadable() )
2443  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to read library "
2444  "document file \"%s\"" ), fn.GetFullPath() ) );
2445 
2446  FILE_LINE_READER reader( fn.GetFullPath() );
2447 
2448  line = reader.ReadLine();
2449 
2450  if( !line )
2451  THROW_IO_ERROR( _( "symbol document library file is empty" ) );
2452 
2453  if( !strCompare( DOCFILE_IDENT, line, &line ) )
2454  SCH_PARSE_ERROR( "invalid document library file version formatting in header",
2455  reader, line );
2456 
2457  while( reader.ReadLine() )
2458  {
2459  line = reader.Line();
2460 
2461  if( *line == '#' ) // Comment line.
2462  continue;
2463 
2464  if( !strCompare( "$CMP", line, &line ) != 0 )
2465  SCH_PARSE_ERROR( "$CMP command expected", reader, line );
2466 
2467  parseUnquotedString( aliasName, reader, line, &line ); // Alias name.
2468  aliasName = LIB_ID::FixIllegalChars( aliasName, LIB_ID::ID_SCH );
2469  LIB_ALIAS_MAP::iterator it = m_aliases.find( aliasName );
2470 
2471  if( it == m_aliases.end() )
2472  wxLogWarning( "Alias '%s' not found in library:\n\n"
2473  "'%s'\n\nat line %d offset %d", aliasName, fn.GetFullPath(),
2474  reader.LineNumber(), (int) (line - reader.Line() ) );
2475  else
2476  alias = it->second;
2477 
2478  // Read the curent alias associated doc.
2479  // if the alias does not exist, just skip the description
2480  // (Can happen if a .dcm is not synchronized with the corresponding .lib file)
2481  while( reader.ReadLine() )
2482  {
2483  line = reader.Line();
2484 
2485  if( !line )
2486  SCH_PARSE_ERROR( "unexpected end of file", reader, line );
2487 
2488  if( strCompare( "$ENDCMP", line, &line ) )
2489  break;
2490 
2491  text = FROM_UTF8( line + 2 );
2492  // Remove spaces at eol, and eol chars:
2493  text = text.Trim();
2494 
2495  switch( line[0] )
2496  {
2497  case 'D':
2498  if( alias )
2499  alias->SetDescription( text );
2500  break;
2501 
2502  case 'K':
2503  if( alias )
2504  alias->SetKeyWords( text );
2505  break;
2506 
2507  case 'F':
2508  if( alias )
2509  alias->SetDocFileName( text );
2510  break;
2511 
2512  case 0:
2513  case '\n':
2514  case '\r':
2515  case '#':
2516  // Empty line or commment
2517  break;
2518 
2519  default:
2520  SCH_PARSE_ERROR( "expected token in symbol definition", reader, line );
2521  }
2522  }
2523  }
2524 }
2525 
2526 
2528 {
2529  const char* line = aReader.Line();
2530 
2531  wxASSERT( strCompare( "$HEADER", line, &line ) );
2532 
2533  while( aReader.ReadLine() )
2534  {
2535  line = (char*) aReader;
2536 
2537  // The time stamp saved in old library files is not used or saved in the latest
2538  // library file version.
2539  if( strCompare( "TimeStamp", line, &line ) )
2540  continue;
2541  else if( strCompare( "$ENDHEADER", line, &line ) )
2542  return;
2543  }
2544 
2545  SCH_PARSE_ERROR( "$ENDHEADER not found", aReader, line );
2546 }
2547 
2548 
2550 {
2551  const char* line = aReader.Line();
2552 
2553  wxCHECK( strCompare( "DEF", line, &line ), NULL );
2554 
2555  // Read DEF line:
2556  char yes_no = 0;
2557 
2558  std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) );
2559 
2560  wxString name, prefix;
2561 
2562  parseUnquotedString( name, aReader, line, &line ); // Part name.
2563  parseUnquotedString( prefix, aReader, line, &line ); // Prefix name
2564  parseInt( aReader, line, &line ); // NumOfPins, unused.
2565  part->SetPinNameOffset( parseInt( aReader, line, &line ) ); // Pin name offset.
2566  yes_no = parseChar( aReader, line, &line ); // Show pin numbers.
2567 
2568  if( !( yes_no == 'Y' || yes_no == 'N') )
2569  SCH_PARSE_ERROR( "expected Y or N", aReader, line );
2570 
2571  part->SetShowPinNumbers( ( yes_no == 'N' ) ? false : true );
2572 
2573  yes_no = parseChar( aReader, line, &line ); // Show pin numbers.
2574 
2575  if( !( yes_no == 'Y' || yes_no == 'N') )
2576  SCH_PARSE_ERROR( "expected Y or N", aReader, line );
2577 
2578  part->SetShowPinNames( ( yes_no == 'N' ) ? false : true ); // Show pin names.
2579 
2580  part->SetUnitCount( parseInt( aReader, line, &line ) ); // Number of units.
2581 
2582  // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
2583  if( part->GetUnitCount() < 1 )
2584  part->SetUnitCount( 1 );
2585 
2586  // Copy part name and prefix.
2587 
2588  // The root alias is added to the alias list by SetName() which is called by SetText().
2589  if( name.IsEmpty() )
2590  {
2591  part->SetName( "~" );
2592  }
2593  else if( name[0] != '~' )
2594  {
2595  part->SetName( name );
2596  }
2597  else
2598  {
2599  part->SetName( name.Right( name.Length() - 1 ) );
2600  part->GetValueField().SetVisible( false );
2601  }
2602 
2603  // Don't set the library alias, this is determined by the symbol library table.
2604  part->SetLibId( LIB_ID( wxEmptyString, part->GetName() ) );
2605 
2606  // There are some code paths in SetText() that do not set the root alias to the
2607  // alias list so add it here if it didn't get added by SetText().
2608  if( !part->HasAlias( part->GetName() ) )
2609  part->AddAlias( part->GetName() );
2610 
2611  LIB_FIELD& reference = part->GetReferenceField();
2612 
2613  if( prefix == "~" )
2614  {
2615  reference.Empty();
2616  reference.SetVisible( false );
2617  }
2618  else
2619  {
2620  reference.SetText( prefix );
2621  }
2622 
2623  // In version 2.2 and earlier, this parameter was a '0' which was just a place holder.
2624  // The was no concept of interchangeable multiple unit symbols.
2626  {
2627  // Nothing needs to be set since the default setting for symbols with multiple
2628  // units were never interchangeable. Just parse the 0 an move on.
2629  parseInt( aReader, line, &line );
2630  }
2631  else
2632  {
2633  char locked = parseChar( aReader, line, &line );
2634 
2635  if( locked == 'L' )
2636  part->LockUnits( true );
2637  else if( locked == 'F' || locked == '0' )
2638  part->LockUnits( false );
2639  else
2640  SCH_PARSE_ERROR( "expected L, F, or 0", aReader, line );
2641  }
2642 
2643 
2644  // There is the optional power component flag.
2645  if( *line )
2646  {
2647  char power = parseChar( aReader, line, &line );
2648 
2649  if( power == 'P' )
2650  part->SetPower();
2651  else if( power == 'N' )
2652  part->SetNormal();
2653  else
2654  SCH_PARSE_ERROR( "expected P or N", aReader, line );
2655  }
2656 
2657  line = aReader.ReadLine();
2658 
2659  // Read lines until "ENDDEF" is found.
2660  while( line )
2661  {
2662  if( *line == '#' ) // Comment
2663  ;
2664  else if( strCompare( "Ti", line, &line ) ) // Modification date is ignored.
2665  continue;
2666  else if( strCompare( "ALIAS", line, &line ) ) // Aliases
2667  loadAliases( part, aReader );
2668  else if( *line == 'F' ) // Fields
2669  loadField( part, aReader );
2670  else if( strCompare( "DRAW", line, &line ) ) // Drawing objects.
2671  loadDrawEntries( part, aReader );
2672  else if( strCompare( "$FPLIST", line, &line ) ) // Footprint filter list
2673  loadFootprintFilters( part, aReader );
2674  else if( strCompare( "ENDDEF", line, &line ) ) // End of part description
2675  {
2676  // Add aliases
2677  for( size_t ii = 0; ii < part->GetAliasCount(); ++ii )
2678  {
2679  LIB_ALIAS* alias = part->GetAlias( ii );
2680  const wxString& aliasName = alias->GetName();
2681  auto it = m_aliases.find( aliasName );
2682 
2683  if( it != m_aliases.end() )
2684  {
2685  // Find a new name for the alias
2686  wxString newName;
2687  int idx = 0;
2688  LIB_ALIAS_MAP::const_iterator jt;
2689 
2690  do
2691  {
2692  newName = wxString::Format( "%s_%d", aliasName, idx );
2693  jt = m_aliases.find( newName );
2694  ++idx;
2695  }
2696  while( jt != m_aliases.end() );
2697 
2698  wxLogWarning( "Symbol name conflict in library:\n%s\n"
2699  "'%s' has been renamed to '%s'",
2700  m_fileName, aliasName, newName );
2701 
2702  if( alias->IsRoot() )
2703  part->SetName( newName );
2704  else
2705  alias->SetName( newName );
2706 
2707  m_aliases[newName] = alias;
2708  }
2709  else
2710  {
2711  m_aliases[aliasName] = alias;
2712  }
2713  }
2714 
2715  return part.release();
2716  }
2717 
2718  line = aReader.ReadLine();
2719  }
2720 
2721  SCH_PARSE_ERROR( "missing ENDDEF", aReader, line );
2722 }
2723 
2724 
2726 {
2727  wxCHECK_MSG( !aAliasName.IsEmpty(), false, "alias name cannot be empty" );
2728 
2729  // The alias name is not a duplicate so don't change it.
2730  if( m_aliases.find( aAliasName ) == m_aliases.end() )
2731  return false;
2732 
2733  int dupCounter = 1;
2734  wxString newAlias = aAliasName;
2735 
2736  // If the alias is already loaded, the library is broken. It may have been possible in
2737  // the past that this could happen so we assign a new alias name to prevent any conflicts
2738  // rather than throw an exception.
2739  while( m_aliases.find( newAlias ) != m_aliases.end() )
2740  {
2741  newAlias = aAliasName << dupCounter;
2742  dupCounter++;
2743  }
2744 
2745  aAliasName = newAlias;
2746 
2747  return true;
2748 }
2749 
2750 
2751 void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr< LIB_PART >& aPart,
2752  FILE_LINE_READER& aReader )
2753 {
2754  wxString newAlias;
2755  const char* line = aReader.Line();
2756 
2757  wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
2758 
2759  // Parse the ALIAS list.
2760  wxString alias;
2761  parseUnquotedString( alias, aReader, line, &line );
2762 
2763  while( !alias.IsEmpty() )
2764  {
2765  newAlias = alias;
2766  checkForDuplicates( newAlias );
2767  aPart->AddAlias( newAlias );
2768  alias.clear();
2769  parseUnquotedString( alias, aReader, line, &line, true );
2770  }
2771 }
2772 
2773 
2774 void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr< LIB_PART >& aPart,
2775  FILE_LINE_READER& aReader )
2776 {
2777  const char* line = aReader.Line();
2778 
2779  wxCHECK_RET( *line == 'F', "Invalid field line" );
2780 
2781  int id;
2782 
2783  if( sscanf( line + 1, "%d", &id ) != 1 || id < 0 )
2784  SCH_PARSE_ERROR( "invalid field ID", aReader, line + 1 );
2785 
2786  LIB_FIELD* field;
2787 
2788  if( (unsigned) id < MANDATORY_FIELDS )
2789  {
2790  field = aPart->GetField( id );
2791 
2792  // this will fire only if somebody broke a constructor or editor.
2793  // MANDATORY_FIELDS are always present in ram resident components, no
2794  // exceptions, and they always have their names set, even fixed fields.
2795  wxASSERT( field );
2796  }
2797  else
2798  {
2799  field = new LIB_FIELD( aPart.get(), id );
2800  aPart->AddDrawItem( field );
2801  }
2802 
2803  // Skip to the first double quote.
2804  while( *line != '"' && *line != 0 )
2805  line++;
2806 
2807  if( *line == 0 )
2808  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, line );
2809 
2810  parseQuotedString( field->m_Text, aReader, line, &line, true );
2811 
2812  // Doctor the *.lib file field which has a "~" in blank fields. New saves will
2813  // not save like this.
2814  if( field->m_Text.size() == 1 && field->m_Text[0] == '~' )
2815  field->m_Text.clear();
2816 
2817  wxPoint pos;
2818 
2819  pos.x = parseInt( aReader, line, &line );
2820  pos.y = parseInt( aReader, line, &line );
2821  field->SetPosition( pos );
2822 
2823  wxSize textSize;
2824 
2825  textSize.x = textSize.y = parseInt( aReader, line, &line );
2826  field->SetTextSize( textSize );
2827 
2828  char textOrient = parseChar( aReader, line, &line );
2829 
2830  if( textOrient == 'H' )
2831  field->SetTextAngle( TEXT_ANGLE_HORIZ );
2832  else if( textOrient == 'V' )
2833  field->SetTextAngle( TEXT_ANGLE_VERT );
2834  else
2835  SCH_PARSE_ERROR( "invalid field text orientation parameter", aReader, line );
2836 
2837  char textVisible = parseChar( aReader, line, &line );
2838 
2839  if( textVisible == 'V' )
2840  field->SetVisible( true );
2841  else if ( textVisible == 'I' )
2842  field->SetVisible( false );
2843  else
2844  SCH_PARSE_ERROR( "invalid field text visibility parameter", aReader, line );
2845 
2846  // It may be technically correct to use the library version to determine if the field text
2847  // attributes are present. If anyone knows if that is valid and what version that would be,
2848  // please change this to test the library version rather than an EOL or the quoted string
2849  // of the field name.
2850  if( *line != 0 && *line != '"' )
2851  {
2852  char textHJustify = parseChar( aReader, line, &line );
2853 
2854  if( textHJustify == 'C' )
2856  else if( textHJustify == 'L' )
2858  else if( textHJustify == 'R' )
2860  else
2861  SCH_PARSE_ERROR( "invalid field text horizontal justification", aReader, line );
2862 
2863  wxString attributes;
2864 
2865  parseUnquotedString( attributes, aReader, line, &line );
2866 
2867  size_t attrSize = attributes.size();
2868 
2869  if( !(attrSize == 3 || attrSize == 1 ) )
2870  SCH_PARSE_ERROR( "invalid field text attributes size", aReader, line );
2871 
2872  switch( (wxChar) attributes[0] )
2873  {
2874  case 'C': field->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
2875  case 'B': field->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
2876  case 'T': field->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
2877  default: SCH_PARSE_ERROR( "invalid field text vertical justification", aReader, line );
2878  }
2879 
2880  if( attrSize == 3 )
2881  {
2882  wxChar attr_1 = attributes[1];
2883  wxChar attr_2 = attributes[2];
2884 
2885  if( attr_1 == 'I' ) // Italic
2886  field->SetItalic( true );
2887  else if( attr_1 != 'N' ) // No italics is default, check for error.
2888  SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
2889 
2890  if ( attr_2 == 'B' ) // Bold
2891  field->SetBold( true );
2892  else if( attr_2 != 'N' ) // No bold is default, check for error.
2893  SCH_PARSE_ERROR( "invalid field text bold parameter", aReader, line );
2894  }
2895  }
2896 
2897  // Fields in RAM must always have names.
2898  if( (unsigned) id < MANDATORY_FIELDS )
2899  {
2900  // Fields in RAM must always have names, because we are trying to get
2901  // less dependent on field ids and more dependent on names.
2902  // Plus assumptions are made in the field editors.
2904 
2905  // Ensure the VALUE field = the part name (can be not the case
2906  // with malformed libraries: edited by hand, or converted from other tools)
2907  if( id == VALUE )
2908  field->m_Text = aPart->GetName();
2909  }
2910  else
2911  {
2912  parseQuotedString( field->m_name, aReader, line, &line, true ); // Optional.
2913  }
2914 }
2915 
2916 
2917 void SCH_LEGACY_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
2918  FILE_LINE_READER& aReader )
2919 {
2920  const char* line = aReader.Line();
2921 
2922  wxCHECK_RET( strCompare( "DRAW", line, &line ), "Invalid DRAW section" );
2923 
2924  line = aReader.ReadLine();
2925 
2926  while( line )
2927  {
2928  if( strCompare( "ENDDRAW", line, &line ) )
2929  return;
2930 
2931  switch( line[0] )
2932  {
2933  case 'A': // Arc
2934  aPart->AddDrawItem( loadArc( aPart, aReader ) );
2935  break;
2936 
2937  case 'C': // Circle
2938  aPart->AddDrawItem( loadCircle( aPart, aReader ) );
2939  break;
2940 
2941  case 'T': // Text
2942  aPart->AddDrawItem( loadText( aPart, aReader ) );
2943  break;
2944 
2945  case 'S': // Square
2946  aPart->AddDrawItem( loadRectangle( aPart, aReader ) );
2947  break;
2948 
2949  case 'X': // Pin Description
2950  aPart->AddDrawItem( loadPin( aPart, aReader ) );
2951  break;
2952 
2953  case 'P': // Polyline
2954  aPart->AddDrawItem( loadPolyLine( aPart, aReader ) );
2955  break;
2956 
2957  case 'B': // Bezier Curves
2958  aPart->AddDrawItem( loadBezier( aPart, aReader ) );
2959  break;
2960 
2961  case '#': // Comment
2962  case '\n': // Empty line
2963  case '\r':
2964  case 0:
2965  break;
2966 
2967  default:
2968  SCH_PARSE_ERROR( "undefined DRAW entry", aReader, line );
2969  }
2970 
2971  line = aReader.ReadLine();
2972  }
2973 
2974  SCH_PARSE_ERROR( "file ended prematurely loading component draw element", aReader, line );
2975 }
2976 
2977 
2979  const char** aOutput )
2980 {
2981  switch( parseChar( aReader, aLine, aOutput ) )
2982  {
2983  case 'F': return FILLED_SHAPE;
2984  case 'f': return FILLED_WITH_BG_BODYCOLOR;
2985  case 'N': return NO_FILL;
2986  default: SCH_PARSE_ERROR( "invalid fill type, expected f, F, or N", aReader, aLine );
2987  }
2988 }
2989 
2990 
2991 LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr< LIB_PART >& aPart,
2992  FILE_LINE_READER& aReader )
2993 {
2994  const char* line = aReader.Line();
2995 
2996  wxCHECK_MSG( strCompare( "A", line, &line ), NULL, "Invalid LIB_ARC definition" );
2997 
2998  LIB_ARC* arc = new LIB_ARC( aPart.get() );
2999 
3000  wxPoint center;
3001 
3002  center.x = parseInt( aReader, line, &line );
3003  center.y = parseInt( aReader, line, &line );
3004 
3005  arc->SetPosition( center );
3006  arc->SetRadius( parseInt( aReader, line, &line ) );
3007 
3008  int angle1 = parseInt( aReader, line, &line );
3009  int angle2 = parseInt( aReader, line, &line );
3010 
3011  NORMALIZE_ANGLE_POS( angle1 );
3012  NORMALIZE_ANGLE_POS( angle2 );
3013  arc->SetFirstRadiusAngle( angle1 );
3014  arc->SetSecondRadiusAngle( angle2 );
3015 
3016  arc->SetUnit( parseInt( aReader, line, &line ) );
3017  arc->SetConvert( parseInt( aReader, line, &line ) );
3018  arc->SetWidth( parseInt( aReader, line, &line ) );
3019 
3020  // Old libraries (version <= 2.2) do not have always this FILL MODE param
3021  // when fill mode is no fill (default mode).
3022  if( *line != 0 )
3023  arc->SetFillMode( parseFillMode( aReader, line, &line ) );
3024 
3025  // Actual Coordinates of arc ends are read from file
3026  if( *line != 0 )
3027  {
3028  wxPoint arcStart, arcEnd;
3029 
3030  arcStart.x = parseInt( aReader, line, &line );
3031  arcStart.y = parseInt( aReader, line, &line );
3032  arcEnd.x = parseInt( aReader, line, &line );
3033  arcEnd.y = parseInt( aReader, line, &line );
3034 
3035  arc->SetStart( arcStart );
3036  arc->SetEnd( arcEnd );
3037  }
3038  else
3039  {
3040  // Actual Coordinates of arc ends are not read from file
3041  // (old library), calculate them
3042  wxPoint arcStart( arc->GetRadius(), 0 );
3043  wxPoint arcEnd( arc->GetRadius(), 0 );
3044 
3045  RotatePoint( &arcStart.x, &arcStart.y, -angle1 );
3046  arcStart += arc->GetPosition();
3047  arc->SetStart( arcStart );
3048  RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 );
3049  arcEnd += arc->GetPosition();
3050  arc->SetEnd( arcEnd );
3051  }
3052 
3053  return arc;
3054 }
3055 
3056 
3057 LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle( std::unique_ptr< LIB_PART >& aPart,
3058  FILE_LINE_READER& aReader )
3059 {
3060  const char* line = aReader.Line();
3061 
3062  wxCHECK_MSG( strCompare( "C", line, &line ), NULL, "Invalid LIB_CIRCLE definition" );
3063 
3064  LIB_CIRCLE* circle = new LIB_CIRCLE( aPart.get() );
3065 
3066  wxPoint center;
3067 
3068  center.x = parseInt( aReader, line, &line );
3069  center.y = parseInt( aReader, line, &line );
3070 
3071  circle->SetPosition( center );
3072  circle->SetRadius( parseInt( aReader, line, &line ) );
3073  circle->SetUnit( parseInt( aReader, line, &line ) );
3074  circle->SetConvert( parseInt( aReader, line, &line ) );
3075  circle->SetWidth( parseInt( aReader, line, &line ) );
3076 
3077  if( *line != 0 )
3078  circle->SetFillMode( parseFillMode( aReader, line, &line ) );
3079 
3080  return circle;
3081 }
3082 
3083 
3084 LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText( std::unique_ptr< LIB_PART >& aPart,
3085  FILE_LINE_READER& aReader )
3086 {
3087  const char* line = aReader.Line();
3088 
3089  wxCHECK_MSG( strCompare( "T", line, &line ), NULL, "Invalid LIB_TEXT definition" );
3090 
3091  LIB_TEXT* text = new LIB_TEXT( aPart.get() );
3092 
3093  text->SetTextAngle( (double) parseInt( aReader, line, &line ) );
3094 
3095  wxPoint center;
3096 
3097  center.x = parseInt( aReader, line, &line );
3098  center.y = parseInt( aReader, line, &line );
3099  text->SetPosition( center );
3100 
3101  wxSize size;
3102 
3103  size.x = size.y = parseInt( aReader, line, &line );
3104  text->SetTextSize( size );
3105  text->SetVisible( !parseInt( aReader, line, &line ) );
3106  text->SetUnit( parseInt( aReader, line, &line ) );
3107  text->SetConvert( parseInt( aReader, line, &line ) );
3108 
3109  wxString str;
3110 
3111  // If quoted string loading fails, load as not quoted string.
3112  if( *line == '"' )
3113  parseQuotedString( str, aReader, line, &line );
3114  else
3115  {
3116  parseUnquotedString( str, aReader, line, &line );
3117 
3118  // In old libs, "spaces" are replaced by '~' in unquoted strings:
3119  str.Replace( "~", " " );
3120  }
3121 
3122  if( !str.IsEmpty() )
3123  {
3124  // convert two apostrophes back to double quote
3125  str.Replace( "''", "\"" );
3126  }
3127 
3128  text->SetText( str );
3129 
3130  // Here things are murky and not well defined. At some point it appears the format
3131  // was changed to add text properties. However rather than add the token to the end of
3132  // the text definition, it was added after the string and no mention if the file
3133  // verion was bumped or not so this code make break on very old component libraries.
3134  //
3135  // Update: apparently even in the latest version this can be different so added a test
3136  // for end of line before checking for the text properties.
3137  if( LIB_VERSION( m_versionMajor, m_versionMinor ) > LIB_VERSION( 2, 0 ) && !is_eol( *line ) )
3138  {
3139  if( strCompare( "Italic", line, &line ) )
3140  text->SetItalic( true );
3141  else if( !strCompare( "Normal", line, &line ) )
3142  SCH_PARSE_ERROR( "invalid text stype, expected 'Normal' or 'Italic'", aReader, line );
3143 
3144  if( parseInt( aReader, line, &line ) > 0 )
3145  text->SetBold( true );
3146 
3147  // Some old libaries version > 2.0 do not have these options for text justification:
3148  if( !is_eol( *line ) )
3149  {
3150  switch( parseChar( aReader, line, &line ) )
3151  {
3152  case 'L': text->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); break;
3153  case 'C': text->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER ); break;
3154  case 'R': text->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); break;
3155  default: SCH_PARSE_ERROR( "invalid horizontal text justication; expected L, C, or R",
3156  aReader, line );
3157  }
3158 
3159  switch( parseChar( aReader, line, &line ) )
3160  {
3161  case 'T': text->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
3162  case 'C': text->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
3163  case 'B': text->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
3164  default: SCH_PARSE_ERROR( "invalid vertical text justication; expected T, C, or B",
3165  aReader, line );
3166  }
3167  }
3168  }
3169 
3170  return text;
3171 }
3172 
3173 
3174 LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle( std::unique_ptr< LIB_PART >& aPart,
3175  FILE_LINE_READER& aReader )
3176 {
3177  const char* line = aReader.Line();
3178 
3179  wxCHECK_MSG( strCompare( "S", line, &line ), NULL, "Invalid LIB_RECTANGLE definition" );
3180 
3181  LIB_RECTANGLE* rectangle = new LIB_RECTANGLE( aPart.get() );
3182 
3183  wxPoint pos;
3184 
3185  pos.x = parseInt( aReader, line, &line );
3186  pos.y = parseInt( aReader, line, &line );
3187  rectangle->SetPosition( pos );
3188 
3189  wxPoint end;
3190 
3191  end.x = parseInt( aReader, line, &line );
3192  end.y = parseInt( aReader, line, &line );
3193  rectangle->SetEnd( end );
3194 
3195  rectangle->SetUnit( parseInt( aReader, line, &line ) );
3196  rectangle->SetConvert( parseInt( aReader, line, &line ) );
3197  rectangle->SetWidth( parseInt( aReader, line, &line ) );
3198 
3199  if( *line != 0 )
3200  rectangle->SetFillMode( parseFillMode( aReader, line, &line ) );
3201 
3202  return rectangle;
3203 }
3204 
3205 
3206 LIB_PIN* SCH_LEGACY_PLUGIN_CACHE::loadPin( std::unique_ptr< LIB_PART >& aPart,
3207  FILE_LINE_READER& aReader )
3208 {
3209  const char* line = aReader.Line();
3210 
3211  wxCHECK_MSG( strCompare( "X", line, &line ), NULL, "Invalid LIB_PIN definition" );
3212 
3213  LIB_PIN* pin = new LIB_PIN( aPart.get() );
3214 
3215  parseUnquotedString( pin->m_name, aReader, line, &line );
3216  parseUnquotedString( pin->m_number, aReader, line, &line );
3217 
3218  wxPoint pos;
3219  pos.x = parseInt( aReader, line, &line );
3220  pos.y = parseInt( aReader, line, &line );
3221  pin->m_position = pos;
3222 
3223  pin->m_length = parseInt( aReader, line, &line );
3224  pin->m_orientation = parseChar( aReader, line, &line );
3225  pin->m_numTextSize = parseInt( aReader, line, &line );
3226  pin->m_nameTextSize = parseInt( aReader, line, &line );
3227  pin->m_Unit = parseInt( aReader, line, &line );
3228  pin->m_Convert = parseInt( aReader, line, &line );
3229 
3230  char type = parseChar( aReader, line, &line );
3231 
3232  wxString attributes;
3233 
3234  // Optional
3235  parseUnquotedString( attributes, aReader, line, &line, true );
3236 
3237  switch( type )
3238  {
3239  case 'I': pin->m_type = PIN_INPUT; break;
3240  case 'O': pin->m_type = PIN_OUTPUT; break;
3241  case 'B': pin->m_type = PIN_BIDI; break;
3242  case 'T': pin->m_type = PIN_TRISTATE; break;
3243  case 'P': pin->m_type = PIN_PASSIVE; break;
3244  case 'U': pin->m_type = PIN_UNSPECIFIED; break;
3245  case 'W': pin->m_type = PIN_POWER_IN; break;
3246  case 'w': pin->m_type = PIN_POWER_OUT; break;
3247  case 'C': pin->m_type = PIN_OPENCOLLECTOR; break;
3248  case 'E': pin->m_type = PIN_OPENEMITTER; break;
3249  case 'N': pin->m_type = PIN_NC; break;
3250  default: SCH_PARSE_ERROR( "unknown pin type", aReader, line );
3251  }
3252 
3253  if( !attributes.IsEmpty() ) /* Special Symbol defined */
3254  {
3255  enum
3256  {
3257  INVERTED = 1 << 0,
3258  CLOCK = 1 << 1,
3259  LOWLEVEL_IN = 1 << 2,
3260  LOWLEVEL_OUT = 1 << 3,
3261  FALLING_EDGE = 1 << 4,
3262  NONLOGIC = 1 << 5
3263  };
3264 
3265  int flags = 0;
3266 
3267  for( int j = attributes.size(); j > 0; )
3268  {
3269  switch( attributes[--j].GetValue() )
3270  {
3271  case '~': break;
3272  case 'N': pin->m_attributes |= PIN_INVISIBLE; break;
3273  case 'I': flags |= INVERTED; break;
3274  case 'C': flags |= CLOCK; break;
3275  case 'L': flags |= LOWLEVEL_IN; break;
3276  case 'V': flags |= LOWLEVEL_OUT; break;
3277  case 'F': flags |= FALLING_EDGE; break;
3278  case 'X': flags |= NONLOGIC; break;
3279  default: SCH_PARSE_ERROR( "unknown pin attribute", aReader, line );
3280  }
3281  }
3282 
3283  switch( flags )
3284  {
3285  case 0: pin->m_shape = PINSHAPE_LINE; break;
3286  case INVERTED: pin->m_shape = PINSHAPE_INVERTED; break;
3287  case CLOCK: pin->m_shape = PINSHAPE_CLOCK; break;
3288  case INVERTED | CLOCK: pin->m_shape = PINSHAPE_INVERTED_CLOCK; break;
3289  case LOWLEVEL_IN: pin->m_shape = PINSHAPE_INPUT_LOW; break;
3290  case LOWLEVEL_IN | CLOCK: pin->m_shape = PINSHAPE_CLOCK_LOW; break;
3291  case LOWLEVEL_OUT: pin->m_shape = PINSHAPE_OUTPUT_LOW; break;
3292  case FALLING_EDGE: pin->m_shape = PINSHAPE_FALLING_EDGE_CLOCK; break;
3293  case NONLOGIC: pin->m_shape = PINSHAPE_NONLOGIC; break;
3294  default: SCH_PARSE_ERROR( "pin attributes do not define a valid pin shape", aReader, line );
3295  }
3296  }
3297 
3298  return pin;
3299 }
3300 
3301 
3302 LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine( std::unique_ptr< LIB_PART >& aPart,
3303  FILE_LINE_READER& aReader )
3304 {
3305  const char* line = aReader.Line();
3306 
3307  wxCHECK_MSG( strCompare( "P", line, &line ), NULL, "Invalid LIB_POLYLINE definition" );
3308 
3309  LIB_POLYLINE* polyLine = new LIB_POLYLINE( aPart.get() );
3310 
3311  int points = parseInt( aReader, line, &line );
3312  polyLine->SetUnit( parseInt( aReader, line, &line ) );
3313  polyLine->SetConvert( parseInt( aReader, line, &line ) );
3314  polyLine->SetWidth( parseInt( aReader, line, &line ) );
3315  polyLine->Reserve( points );
3316 
3317  wxPoint pt;
3318 
3319  for( int i = 0; i < points; i++ )
3320  {
3321  pt.x = parseInt( aReader, line, &line );
3322  pt.y = parseInt( aReader, line, &line );
3323  polyLine->AddPoint( pt );
3324  }
3325 
3326  if( *line != 0 )
3327  polyLine->SetFillMode( parseFillMode( aReader, line, &line ) );
3328 
3329  return polyLine;
3330 }
3331 
3332 
3333 LIB_BEZIER* SCH_LEGACY_PLUGIN_CACHE::loadBezier( std::unique_ptr< LIB_PART >& aPart,
3334  FILE_LINE_READER& aReader )
3335 {
3336  const char* line = aReader.Line();
3337 
3338  wxCHECK_MSG( strCompare( "B", line, &line ), NULL, "Invalid LIB_BEZIER definition" );
3339 
3340  LIB_BEZIER* bezier = new LIB_BEZIER( aPart.get() );
3341 
3342  int points = parseInt( aReader, line, &line );
3343  bezier->SetUnit( parseInt( aReader, line, &line ) );
3344  bezier->SetConvert( parseInt( aReader, line, &line ) );
3345  bezier->SetWidth( parseInt( aReader, line, &line ) );
3346 
3347  wxPoint pt;
3348  bezier->Reserve( points );
3349 
3350  for( int i = 0; i < points; i++ )
3351  {
3352  pt.x = parseInt( aReader, line, &line );
3353  pt.y = parseInt( aReader, line, &line );
3354  bezier->AddPoint( pt );
3355  }
3356 
3357  if( *line != 0 )
3358  bezier->SetFillMode( parseFillMode( aReader, line, &line ) );
3359 
3360  return bezier;
3361 }
3362 
3363 
3364 void SCH_LEGACY_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
3365  FILE_LINE_READER& aReader )
3366 {
3367  const char* line = aReader.Line();
3368 
3369  wxCHECK_RET( strCompare( "$FPLIST", line, &line ), "Invalid footprint filter list" );
3370 
3371  line = aReader.ReadLine();
3372 
3373  while( line )
3374  {
3375  if( strCompare( "$ENDFPLIST", line, &line ) )
3376  return;
3377 
3378  wxString footprint;
3379 
3380  parseUnquotedString( footprint, aReader, line, &line );
3381  aPart->GetFootprints().Add( footprint );
3382  line = aReader.ReadLine();
3383  }
3384 
3385  SCH_PARSE_ERROR( "file ended prematurely while loading footprint filters", aReader, line );
3386 }
3387 
3388 
3389 void SCH_LEGACY_PLUGIN_CACHE::Save( bool aSaveDocFile )
3390 {
3391  if( !m_isModified )
3392  return;
3393 
3394  // Write through symlinks, don't replace them
3395  wxFileName fn = GetRealFile();
3396 
3397  std::unique_ptr< FILE_OUTPUTFORMATTER > formatter( new FILE_OUTPUTFORMATTER( fn.GetFullPath() ) );
3398  formatter->Print( 0, "%s %d.%d\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
3399  formatter->Print( 0, "#encoding utf-8\n");
3400 
3401  for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
3402  {
3403  if( !it->second->IsRoot() )
3404  continue;
3405 
3406  saveSymbol( it->second->GetPart(), formatter );
3407  }
3408 
3409  formatter->Print( 0, "#\n#End Library\n" );
3410  formatter.reset();
3411 
3412  m_fileModTime = fn.GetModificationTime();
3413  m_isModified = false;
3414 
3415  if( aSaveDocFile )
3416  saveDocFile();
3417 }
3418 
3419 
3421  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3422 {
3423  wxCHECK_RET( aSymbol, "Invalid LIB_PART pointer." );
3424 
3425  LIB_FIELD& value = aSymbol->GetValueField();
3426 
3427  // First line: it s a comment (component name for readers)
3428  aFormatter->Print( 0, "#\n# %s\n#\n", TO_UTF8( value.GetText() ) );
3429 
3430  // Save data
3431  aFormatter->Print( 0, "DEF" );
3432 
3433  if( value.IsVisible() )
3434  {
3435  aFormatter->Print( 0, " %s", TO_UTF8( value.GetText() ) );
3436  }
3437  else
3438  {
3439  aFormatter->Print( 0, " ~%s", TO_UTF8( value.GetText() ) );
3440  }
3441 
3442  LIB_FIELD& reference = aSymbol->GetReferenceField();
3443 
3444  if( !reference.GetText().IsEmpty() )
3445  {
3446  aFormatter->Print( 0, " %s", TO_UTF8( reference.GetText() ) );
3447  }
3448  else
3449  {
3450  aFormatter->Print( 0, " ~" );
3451  }
3452 
3453  aFormatter->Print( 0, " %d %d %c %c %d %c %c\n",
3454  0, aSymbol->GetPinNameOffset(),
3455  aSymbol->ShowPinNumbers() ? 'Y' : 'N',
3456  aSymbol->ShowPinNames() ? 'Y' : 'N',
3457  aSymbol->GetUnitCount(), aSymbol->UnitsLocked() ? 'L' : 'F',
3458  aSymbol->IsPower() ? 'P' : 'N' );
3459 
3460  timestamp_t dateModified = aSymbol->GetDateLastEdition();
3461 
3462  if( dateModified != 0 )
3463  {
3464  int sec = dateModified & 63;
3465  int min = ( dateModified >> 6 ) & 63;
3466  int hour = ( dateModified >> 12 ) & 31;
3467  int day = ( dateModified >> 17 ) & 31;
3468  int mon = ( dateModified >> 22 ) & 15;
3469  int year = ( dateModified >> 26 ) + 1990;
3470 
3471  aFormatter->Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec );
3472  }
3473 
3474  LIB_FIELDS fields;
3475  aSymbol->GetFields( fields );
3476 
3477  // Mandatory fields:
3478  // may have their own save policy so there is a separate loop for them.
3479  // Empty fields are saved, because the user may have set visibility,
3480  // size and orientation
3481  for( int i = 0; i < MANDATORY_FIELDS; ++i )
3482  {
3483  saveField( &fields[i], aFormatter );
3484  }
3485 
3486  // User defined fields:
3487  // may have their own save policy so there is a separate loop for them.
3488 
3489  int fieldId = MANDATORY_FIELDS; // really wish this would go away.
3490 
3491  for( unsigned i = MANDATORY_FIELDS; i < fields.size(); ++i )
3492  {
3493  // There is no need to save empty fields, i.e. no reason to preserve field
3494  // names now that fields names come in dynamically through the template
3495  // fieldnames.
3496  if( !fields[i].GetText().IsEmpty() )
3497  {
3498  fields[i].SetId( fieldId++ );
3499  saveField( &fields[i], aFormatter );
3500  }
3501  }
3502 
3503  // Save the alias list: a line starting by "ALIAS". The first alias is the root
3504  // and has the same name as the component. In the old library file format this
3505  // alias does not get added to the alias list.
3506  if( aSymbol->GetAliasCount() > 1 )
3507  {
3508  wxArrayString aliases = aSymbol->GetAliasNames();
3509 
3510  aFormatter->Print( 0, "ALIAS" );
3511 
3512  for( unsigned i = 1; i < aliases.size(); i++ )
3513  {
3514  aFormatter->Print( 0, " %s", TO_UTF8( aliases[i] ) );
3515  }
3516 
3517  aFormatter->Print( 0, "\n" );
3518  }
3519 
3520  wxArrayString footprints = aSymbol->GetFootprints();
3521 
3522  // Write the footprint filter list
3523  if( footprints.GetCount() != 0 )
3524  {
3525  aFormatter->Print( 0, "$FPLIST\n" );
3526 
3527  for( unsigned i = 0; i < footprints.GetCount(); i++ )
3528  {
3529  aFormatter->Print( 0, " %s\n", TO_UTF8( footprints[i] ) );
3530  }
3531 
3532  aFormatter->Print( 0, "$ENDFPLIST\n" );
3533  }
3534 
3535  // Save graphics items (including pins)
3536  if( !aSymbol->GetDrawItems().empty() )
3537  {
3538  // Sort the draw items in order to editing a file editing by hand.
3539  aSymbol->GetDrawItems().sort();
3540 
3541  aFormatter->Print( 0, "DRAW\n" );
3542 
3543  for( LIB_ITEM& item : aSymbol->GetDrawItems() )
3544  {
3545  switch( item.Type() )
3546  {
3547  case LIB_FIELD_T: // Fields have already been saved above.
3548  continue;
3549 
3550  case LIB_ARC_T:
3551  saveArc( (LIB_ARC*) &item, aFormatter );
3552  break;
3553 
3554  case LIB_BEZIER_T:
3555  saveBezier( (LIB_BEZIER*) &item, aFormatter );
3556  break;
3557 
3558  case LIB_CIRCLE_T:
3559  saveCircle( ( LIB_CIRCLE* ) &item, aFormatter );
3560  break;
3561 
3562  case LIB_PIN_T:
3563  savePin( (LIB_PIN* ) &item, aFormatter );
3564  break;
3565 
3566  case LIB_POLYLINE_T:
3567  savePolyLine( ( LIB_POLYLINE* ) &item, aFormatter );
3568  break;
3569 
3570  case LIB_RECTANGLE_T:
3571  saveRectangle( ( LIB_RECTANGLE* ) &item, aFormatter );
3572  break;
3573 
3574  case LIB_TEXT_T:
3575  saveText( ( LIB_TEXT* ) &item, aFormatter );
3576  break;
3577 
3578  default:
3579  ;
3580  }
3581  }
3582 
3583  aFormatter->Print( 0, "ENDDRAW\n" );
3584  }
3585 
3586  aFormatter->Print( 0, "ENDDEF\n" );
3587 }
3588 
3589 
3591  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3592 {
3593  wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." );
3594 
3595  int x1 = aArc->GetFirstRadiusAngle();
3596 
3597  if( x1 > 1800 )
3598  x1 -= 3600;
3599 
3600  int x2 = aArc->GetSecondRadiusAngle();
3601 
3602  if( x2 > 1800 )
3603  x2 -= 3600;
3604 
3605  aFormatter->Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n",
3606  aArc->GetPosition().x, aArc->GetPosition().y,
3607  aArc->GetRadius(), x1, x2, aArc->GetUnit(), aArc->GetConvert(),
3608  aArc->GetWidth(), fill_tab[aArc->GetFillMode()],
3609  aArc->GetStart().x, aArc->GetStart().y,
3610  aArc->GetEnd().x, aArc->GetEnd().y );
3611 }
3612 
3613 
3615  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3616 {
3617  wxCHECK_RET( aBezier && aBezier->Type() == LIB_BEZIER_T, "Invalid LIB_BEZIER object." );
3618 
3619  aFormatter->Print( 0, "B %u %d %d %d", (unsigned)aBezier->GetPoints().size(),
3620  aBezier->GetUnit(), aBezier->GetConvert(), aBezier->GetWidth() );
3621 
3622  for( const auto& pt : aBezier->GetPoints() )
3623  aFormatter->Print( 0, " %d %d", pt.x, pt.y );
3624 
3625  aFormatter->Print( 0, " %c\n", fill_tab[aBezier->GetFillMode()] );
3626 }
3627 
3628 
3630  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3631 {
3632  wxCHECK_RET( aCircle && aCircle->Type() == LIB_CIRCLE_T, "Invalid LIB_CIRCLE object." );
3633 
3634  aFormatter->Print( 0, "C %d %d %d %d %d %d %c\n",
3635  aCircle->GetPosition().x, aCircle->GetPosition().y,
3636  aCircle->GetRadius(), aCircle->GetUnit(), aCircle->GetConvert(),
3637  aCircle->GetWidth(), fill_tab[aCircle->GetFillMode()] );
3638 }
3639 
3640 
3642  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3643 {
3644  wxCHECK_RET( aField && aField->Type() == LIB_FIELD_T, "Invalid LIB_FIELD object." );
3645 
3646  int hjustify, vjustify;
3647  int id = aField->GetId();
3648  wxString text = aField->m_Text;
3649 
3650  hjustify = 'C';
3651 
3652  if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
3653  hjustify = 'L';
3654  else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
3655  hjustify = 'R';
3656 
3657  vjustify = 'C';
3658 
3659  if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
3660  vjustify = 'B';
3661  else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
3662  vjustify = 'T';
3663 
3664  aFormatter->Print( 0, "F%d %s %d %d %d %c %c %c %c%c%c",
3665  id,
3666  EscapedUTF8( text ).c_str(), // wraps in quotes
3667  aField->GetTextPos().x, aField->GetTextPos().y, aField->GetTextWidth(),
3668  aField->GetTextAngle() == 0 ? 'H' : 'V',
3669  aField->IsVisible() ? 'V' : 'I',
3670  hjustify, vjustify,
3671  aField->IsItalic() ? 'I' : 'N',
3672  aField->IsBold() ? 'B' : 'N' );
3673 
3674  /* Save field name, if necessary
3675  * Field name is saved only if it is not the default name.
3676  * Just because default name depends on the language and can change from
3677  * a country to another
3678  */
3679  wxString defName = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
3680 
3681  if( id >= FIELD1 && !aField->m_name.IsEmpty() && aField->m_name != defName )
3682  aFormatter->Print( 0, " %s", EscapedUTF8( aField->m_name ).c_str() );
3683 
3684  aFormatter->Print( 0, "\n" );
3685 }
3686 
3687 
3689  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3690 {
3691  wxCHECK_RET( aPin && aPin->Type() == LIB_PIN_T, "Invalid LIB_PIN object." );
3692 
3693  int Etype;
3694 
3695  switch( aPin->GetType() )
3696  {
3697  default:
3698  case PIN_INPUT:
3699  Etype = 'I';
3700  break;
3701 
3702  case PIN_OUTPUT:
3703  Etype = 'O';
3704  break;
3705 
3706  case PIN_BIDI:
3707  Etype = 'B';
3708  break;
3709 
3710  case PIN_TRISTATE:
3711  Etype = 'T';
3712  break;
3713 
3714  case PIN_PASSIVE:
3715  Etype = 'P';
3716  break;
3717 
3718  case PIN_UNSPECIFIED:
3719  Etype = 'U';
3720  break;
3721 
3722  case PIN_POWER_IN:
3723  Etype = 'W';
3724  break;
3725 
3726  case PIN_POWER_OUT:
3727  Etype = 'w';
3728  break;
3729 
3730  case PIN_OPENCOLLECTOR:
3731  Etype = 'C';
3732  break;
3733 
3734  case PIN_OPENEMITTER:
3735  Etype = 'E';
3736  break;
3737 
3738  case PIN_NC:
3739  Etype = 'N';
3740  break;
3741  }
3742 
3743  if( !aPin->GetName().IsEmpty() )
3744  aFormatter->Print( 0, "X %s", TO_UTF8( aPin->GetName() ) );
3745  else
3746  aFormatter->Print( 0, "X ~" );
3747 
3748  aFormatter->Print( 0, " %s %d %d %d %c %d %d %d %d %c",
3749  aPin->GetNumber().IsEmpty() ? "~" : TO_UTF8( aPin->GetNumber() ),
3750  aPin->GetPosition().x, aPin->GetPosition().y,
3751  (int) aPin->GetLength(), (int) aPin->GetOrientation(),
3752  aPin->GetNumberTextSize(), aPin->GetNameTextSize(),
3753  aPin->GetUnit(), aPin->GetConvert(), Etype );
3754 
3755  if( aPin->GetShape() || !aPin->IsVisible() )
3756  aFormatter->Print( 0, " " );
3757 
3758  if( !aPin->IsVisible() )
3759  aFormatter->Print( 0, "N" );
3760 
3761  switch( aPin->GetShape() )
3762  {
3763  case PINSHAPE_LINE:
3764  break;
3765 
3766  case PINSHAPE_INVERTED:
3767  aFormatter->Print( 0, "I" );
3768  break;
3769 
3770  case PINSHAPE_CLOCK:
3771  aFormatter->Print( 0, "C" );
3772  break;
3773 
3775  aFormatter->Print( 0, "IC" );
3776  break;
3777 
3778  case PINSHAPE_INPUT_LOW:
3779  aFormatter->Print( 0, "L" );
3780  break;
3781 
3782  case PINSHAPE_CLOCK_LOW:
3783  aFormatter->Print( 0, "CL" );
3784  break;
3785 
3786  case PINSHAPE_OUTPUT_LOW:
3787  aFormatter->Print( 0, "V" );
3788  break;
3789 
3791  aFormatter->Print( 0, "F" );
3792  break;
3793 
3794  case PINSHAPE_NONLOGIC:
3795  aFormatter->Print( 0, "X" );
3796  break;
3797 
3798  default:
3799  assert( !"Invalid pin shape" );
3800  }
3801 
3802  aFormatter->Print( 0, "\n" );
3803 
3804  aPin->ClearFlags( IS_CHANGED );
3805 }
3806 
3807 
3809  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3810 {
3811  wxCHECK_RET( aPolyLine && aPolyLine->Type() == LIB_POLYLINE_T, "Invalid LIB_POLYLINE object." );
3812 
3813  int ccount = aPolyLine->GetCornerCount();
3814 
3815  aFormatter->Print( 0, "P %d %d %d %d", ccount, aPolyLine->GetUnit(), aPolyLine->GetConvert(),
3816  aPolyLine->GetWidth() );
3817 
3818  for( const auto& pt : aPolyLine->GetPolyPoints() )
3819  {
3820  aFormatter->Print( 0, " %d %d", pt.x, pt.y );
3821  }
3822 
3823  aFormatter->Print( 0, " %c\n", fill_tab[aPolyLine->GetFillMode()] );
3824 }
3825 
3826 
3828  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3829 {
3830  wxCHECK_RET( aRectangle && aRectangle->Type() == LIB_RECTANGLE_T,
3831  "Invalid LIB_RECTANGLE object." );
3832 
3833  aFormatter->Print( 0, "S %d %d %d %d %d %d %d %c\n",
3834  aRectangle->GetPosition().x, aRectangle->GetPosition().y,
3835  aRectangle->GetEnd().x, aRectangle->GetEnd().y,
3836  aRectangle->GetUnit(), aRectangle->GetConvert(),
3837  aRectangle->GetWidth(), fill_tab[aRectangle->GetFillMode()] );
3838 }
3839 
3840 
3842  std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
3843 {
3844  wxCHECK_RET( aText && aText->Type() == LIB_TEXT_T, "Invalid LIB_TEXT object." );
3845 
3846  wxString text = aText->GetText();
3847 
3848  if( text.Contains( wxT( " " ) ) || text.Contains( wxT( "~" ) ) || text.Contains( wxT( "\"" ) ) )
3849  {
3850  // convert double quote to similar-looking two apostrophes
3851  text.Replace( wxT( "\"" ), wxT( "''" ) );
3852  text = wxT( "\"" ) + text + wxT( "\"" );
3853  }
3854 
3855  aFormatter->Print( 0, "T %g %d %d %d %d %d %d %s", aText->GetTextAngle(),
3856  aText->GetTextPos().x, aText->GetTextPos().y,
3857  aText->GetTextWidth(), !aText->IsVisible(),
3858  aText->GetUnit(), aText->GetConvert(), TO_UTF8( text ) );
3859 
3860  aFormatter->Print( 0, " %s %d", aText->IsItalic() ? "Italic" : "Normal", aText->IsBold() );
3861 
3862  char hjustify = 'C';
3863 
3864  if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
3865  hjustify = 'L';
3866  else if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
3867  hjustify = 'R';
3868 
3869  char vjustify = 'C';
3870 
3871  if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
3872  vjustify = 'B';
3873  else if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
3874  vjustify = 'T';
3875 
3876  aFormatter->Print( 0, " %c %c\n", hjustify, vjustify );
3877 }
3878 
3879 
3881 {
3882  wxFileName fileName = m_libFileName;
3883 
3884  fileName.SetExt( DOC_EXT );
3885  FILE_OUTPUTFORMATTER formatter( fileName.GetFullPath() );
3886 
3887  formatter.Print( 0, "%s\n", DOCFILE_IDENT );
3888 
3889  for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
3890  {
3891  wxString description = it->second->GetDescription();
3892  wxString keyWords = it->second->GetKeyWords();
3893  wxString docFileName = it->second->GetDocFileName();
3894 
3895  if( description.IsEmpty() && keyWords.IsEmpty() && docFileName.IsEmpty() )
3896  continue;
3897 
3898  formatter.Print( 0, "#\n$CMP %s\n", TO_UTF8( it->second->GetName() ) );
3899 
3900  if( !description.IsEmpty() )
3901  formatter.Print( 0, "D %s\n", TO_UTF8( description ) );
3902 
3903  if( !keyWords.IsEmpty() )
3904  formatter.Print( 0, "K %s\n", TO_UTF8( keyWords ) );
3905 
3906  if( !docFileName.IsEmpty() )
3907  formatter.Print( 0, "F %s\n", TO_UTF8( docFileName ) );
3908 
3909  formatter.Print( 0, "$ENDCMP\n" );
3910  }
3911 
3912  formatter.Print( 0, "#\n#End Doc Library\n" );
3913 }
3914 
3915 
3916 void SCH_LEGACY_PLUGIN_CACHE::DeleteAlias( const wxString& aAliasName )
3917 {
3918  LIB_ALIAS_MAP::iterator it = m_aliases.find( aAliasName );
3919 
3920  if( it == m_aliases.end() )
3921  THROW_IO_ERROR( wxString::Format( _( "library %s does not contain an alias %s" ),
3922  m_libFileName.GetFullName(), aAliasName ) );
3923 
3924  LIB_ALIAS* alias = it->second;
3925  LIB_PART* part = alias->GetPart();
3926 
3927  alias = part->RemoveAlias( alias );
3928 
3929  if( !alias )
3930  {
3931  delete part;
3932 
3933  if( m_aliases.size() > 1 )
3934  {
3935  LIB_ALIAS_MAP::iterator next = it;
3936  next++;
3937 
3938  if( next == m_aliases.end() )
3939  next = m_aliases.begin();
3940 
3941  alias = next->second;
3942  }
3943  }
3944 
3945  m_aliases.erase( it );
3946  ++m_modHash;
3947  m_isModified = true;
3948 }
3949 
3950 
3951 void SCH_LEGACY_PLUGIN_CACHE::DeleteSymbol( const wxString& aAliasName )
3952 {
3953  LIB_ALIAS_MAP::iterator it = m_aliases.find( aAliasName );
3954 
3955  if( it == m_aliases.end() )
3956  THROW_IO_ERROR( wxString::Format( _( "library %s does not contain an alias %s" ),
3957  m_libFileName.GetFullName(), aAliasName ) );
3958 
3959  LIB_ALIAS* alias = it->second;
3960  LIB_PART* part = alias->GetPart();
3961 
3962  wxArrayString aliasNames = part->GetAliasNames();
3963 
3964  // Deleting all of the aliases deletes the symbol from the library.
3965  for( size_t i = 0; i < aliasNames.Count(); i++ )
3966  DeleteAlias( aliasNames[i] );
3967 }
3968 
3969 
3970 void SCH_LEGACY_PLUGIN::cacheLib( const wxString& aLibraryFileName )
3971 {
3972  if( !m_cache || !m_cache->IsFile( aLibraryFileName ) || m_cache->IsFileChanged() )
3973  {
3974  // a spectacular episode in memory management:
3975  delete m_cache;
3976  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryFileName );
3977 
3978  // Because m_cache is rebuilt, increment PART_LIBS::s_modify_generation
3979  // to modify the hash value that indicate component to symbol links
3980  // must be updated.
3982 
3983  if( !isBuffering( m_props ) )
3984  m_cache->Load();
3985  }
3986 }
3987 
3988 
3990 {
3991  std::string propName( SCH_LEGACY_PLUGIN::PropNoDocFile );
3992 
3993  if( aProperties && aProperties->find( propName ) != aProperties->end() )
3994  return false;
3995 
3996  return true;
3997 }
3998 
3999 
4000 bool SCH_LEGACY_PLUGIN::isBuffering( const PROPERTIES* aProperties )
4001 {
4002  return ( aProperties && aProperties->Exists( SCH_LEGACY_PLUGIN::PropBuffering ) );
4003 }
4004 
4005 
4007 {
4008  if( m_cache )
4009  return m_cache->GetModifyHash();
4010 
4011  // If the cache hasn't been loaded, it hasn't been modified.
4012  return 0;
4013 }
4014 
4015 
4016 size_t SCH_LEGACY_PLUGIN::GetSymbolLibCount( const wxString& aLibraryPath,
4017  const PROPERTIES* aProperties )
4018 {
4019  LOCALE_IO toggle;
4020 
4021  m_props = aProperties;
4022 
4023  cacheLib( aLibraryPath );
4024 
4025  return m_cache->m_aliases.size();
4026 }
4027 
4028 
4029 void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList,
4030  const wxString& aLibraryPath,
4031  const PROPERTIES* aProperties )
4032 {
4033  LOCALE_IO toggle; // toggles on, then off, the C locale.
4034 
4035  m_props = aProperties;
4036 
4037  bool powerSymbolsOnly = ( aProperties &&
4038  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
4039  cacheLib( aLibraryPath );
4040 
4041  const LIB_ALIAS_MAP& aliases = m_cache->m_aliases;
4042 
4043  for( LIB_ALIAS_MAP::const_iterator it = aliases.begin(); it != aliases.end(); ++it )
4044  {
4045  if( !powerSymbolsOnly || it->second->GetPart()->IsPower() )
4046  aAliasNameList.Add( it->first );
4047  }
4048 }
4049 
4050 
4051 void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( std::vector<LIB_ALIAS*>& aAliasList,
4052  const wxString& aLibraryPath,
4053  const PROPERTIES* aProperties )
4054 {
4055  LOCALE_IO toggle; // toggles on, then off, the C locale.
4056 
4057  m_props = aProperties;
4058 
4059  bool powerSymbolsOnly = ( aProperties &&
4060  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
4061  cacheLib( aLibraryPath );
4062 
4063  const LIB_ALIAS_MAP& aliases = m_cache->m_aliases;
4064 
4065  for( LIB_ALIAS_MAP::const_iterator it = aliases.begin(); it != aliases.end(); ++it )
4066  {
4067  if( !powerSymbolsOnly || it->second->GetPart()->IsPower() )
4068  aAliasList.push_back( it->second );
4069  }
4070 }
4071 
4072 
4073 LIB_ALIAS* SCH_LEGACY_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
4074  const PROPERTIES* aProperties )
4075 {
4076  LOCALE_IO toggle; // toggles on, then off, the C locale.
4077 
4078  m_props = aProperties;
4079 
4080  cacheLib( aLibraryPath );
4081 
4082  LIB_ALIAS_MAP::const_iterator it = m_cache->m_aliases.find( aAliasName );
4083 
4084  if( it == m_cache->m_aliases.end() )
4085  return NULL;
4086 
4087  return it->second;
4088 }
4089 
4090 
4091 void SCH_LEGACY_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_PART* aSymbol,
4092  const PROPERTIES* aProperties )
4093 {
4094  m_props = aProperties;
4095 
4096  cacheLib( aLibraryPath );
4097 
4098  m_cache->AddSymbol( aSymbol );
4099 
4100  if( !isBuffering( aProperties ) )
4101  m_cache->Save( writeDocFile( aProperties ) );
4102 }
4103 
4104 
4105 void SCH_LEGACY_PLUGIN::DeleteAlias( const wxString& aLibraryPath, const wxString& aAliasName,
4106  const PROPERTIES* aProperties )
4107 {
4108  m_props = aProperties;
4109 
4110  cacheLib( aLibraryPath );
4111 
4112  m_cache->DeleteAlias( aAliasName );
4113 
4114  if( !isBuffering( aProperties ) )
4115  m_cache->Save( writeDocFile( aProperties ) );
4116 }
4117 
4118 
4119 void SCH_LEGACY_PLUGIN::DeleteSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
4120  const PROPERTIES* aProperties )
4121 {
4122  m_props = aProperties;
4123 
4124  cacheLib( aLibraryPath );
4125 
4126  m_cache->DeleteSymbol( aAliasName );
4127 
4128  if( !isBuffering( aProperties ) )
4129  m_cache->Save( writeDocFile( aProperties ) );
4130 }
4131 
4132 
4133 void SCH_LEGACY_PLUGIN::CreateSymbolLib( const wxString& aLibraryPath,
4134  const PROPERTIES* aProperties )
4135 {
4136  if( wxFileExists( aLibraryPath ) )
4137  {
4139  _( "symbol library \"%s\" already exists, cannot create a new library" ),
4140  aLibraryPath.GetData() ) );
4141  }
4142 
4143  LOCALE_IO toggle;
4144 
4145  m_props = aProperties;
4146 
4147  delete m_cache;
4148  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
4149  m_cache->SetModified();
4150  m_cache->Save( writeDocFile( aProperties ) );
4151  m_cache->Load(); // update m_writable and m_mod_time
4152 }
4153 
4154 
4155 bool SCH_LEGACY_PLUGIN::DeleteSymbolLib( const wxString& aLibraryPath,
4156  const PROPERTIES* aProperties )
4157 {
4158  wxFileName fn = aLibraryPath;
4159 
4160  if( !fn.FileExists() )
4161  return false;
4162 
4163  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
4164  // we don't want that. we want bare metal portability with no UI here.
4165  if( wxRemove( aLibraryPath ) )
4166  {
4167  THROW_IO_ERROR( wxString::Format( _( "library \"%s\" cannot be deleted" ),
4168  aLibraryPath.GetData() ) );
4169  }
4170 
4171  if( m_cache && m_cache->IsFile( aLibraryPath ) )
4172  {
4173  delete m_cache;
4174  m_cache = 0;
4175  }
4176 
4177  return true;
4178 }
4179 
4180 
4181 void SCH_LEGACY_PLUGIN::SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties )
4182 {
4183  if( !m_cache )
4184  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
4185 
4186  wxString oldFileName = m_cache->GetFileName();
4187 
4188  if( !m_cache->IsFile( aLibraryPath ) )
4189  {
4190  m_cache->SetFileName( aLibraryPath );
4191  }
4192 
4193  // This is a forced save.
4194  m_cache->SetModified();
4195  m_cache->Save( writeDocFile( aProperties ) );
4196  m_cache->SetFileName( oldFileName );
4197 }
4198 
4199 
4200 bool SCH_LEGACY_PLUGIN::CheckHeader( const wxString& aFileName )
4201 {
4202  // Open file and check first line
4203  wxTextFile tempFile;
4204 
4205  tempFile.Open( aFileName );
4206  wxString firstline;
4207  // read the first line
4208  firstline = tempFile.GetFirstLine();
4209  tempFile.Close();
4210 
4211  return firstline.StartsWith( "EESchema" );
4212 }
4213 
4214 
4215 bool SCH_LEGACY_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath )
4216 {
4217  return wxFileName::IsFileWritable( aLibraryPath );
4218 }
4219 
4220 
4221 const char* SCH_LEGACY_PLUGIN::PropBuffering = "buffering";
4222 const char* SCH_LEGACY_PLUGIN::PropNoDocFile = "no_doc_file";
void SetTextAngle(double aAngle)
Definition: eda_text.h:169
void SetComment1(const wxString &aComment)
Definition: title_block.h:117
#define TEXT_ANGLE_HORIZ
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:201
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.
SCH_BITMAP * loadBitmap(FILE_LINE_READER &aReader)
LIB_PIN * loadPin(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
int m_nameTextSize
Pin num and Pin name sizes.
Definition: lib_pin.h:85
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:435
int m_ScreenNumber
Definition: base_screen.h:216
FILL_T GetFillMode() const
wxString m_Text
Definition: eda_text.h:374
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.
GRAPHIC_PINSHAPE m_shape
Shape drawn around pin.
Definition: lib_pin.h:78
int GetPinNameOffset()
const wxPoint & GetTextPos() const
Definition: eda_text.h:237
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:52
wxPoint GetStart() const
Definition: lib_arc.h:148
int y2
Definition: transform.h:51
bool IsItalic() const
Definition: eda_text.h:183
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:179
bool IsPower() const
void SetPosition(const wxPoint &aPosition)
const wxString & GetCompany() const
Definition: title_block.h:99
Helper class to create more flexible dialogs, including &#39;do not show again&#39; checkbox handling...
Definition: confirm.h:44
#define TEXT_ANGLE_VERT
static int s_modify_generation
helper for GetModifyHash()
int GetUnit() const
This file is part of the common library.
int m_numTextSize
Definition: lib_pin.h:84
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:84
Define a symbol library graphical text item.
Definition: lib_text.h:44
void saveLine(SCH_LINE *aLine)
COLOR4D GetLineColor() const
Definition: sch_line.cpp:243
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.
void SetItalic(bool isItalic)
Definition: eda_text.h:182
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:231
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:131
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:77
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:188
void sort()
Definition: multivector.h:229
void SetFirstRadiusAngle(int aAngle)
Definition: lib_arc.h:140
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:68
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:124
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Definition: title_block.h:74
SCH_LEGACY_PLUGIN_CACHE(const wxString &aLibraryPath)
int m_Unit
Unit identification for multiple parts per package.
bool Exists(const std::string &aProperty) const
Definition: properties.h:44
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:127
#define LIB_VERSION(major, minor)
Definition: class_library.h:61
wxString m_name
Definition: lib_pin.h:82
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:66
const std::vector< wxPoint > & GetPoints() const
Definition: lib_bezier.h:76
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:79
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...
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:49
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:78
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 SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:227
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:157
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:192
void loadHeader(FILE_LINE_READER &aReader)
int GetWidth() const override
Return the width of the draw item.
Definition: lib_circle.h:97
void SetWidth(int aWidth) override
Set the width of the draw item to aWidth.
Definition: lib_polyline.h:115
int GetOrientation() const
Definition: lib_pin.h:221
int m_length
Length of the pin.
Definition: lib_pin.h:76
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:40
void SetDocFileName(const wxString &aDocFileName)
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:203
#define T_WIDTH
SCH_ITEM * Next() const
unsigned GetCornerCount() const
Definition: lib_polyline.h:78
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:219
int GetWidth() const override
Return the width of the draw item.
Definition: lib_polyline.h:113
bool IsBold() const
Definition: eda_text.h:186
double GetTextAngle() const
Definition: eda_text.h:177
The base class for drawable items used by schematic library components.
Definition: lib_draw_item.h:67
void SetComment4(const wxString &aComment)
Definition: title_block.h:120
const wxString & GetNumber() const
Definition: lib_pin.h:194
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:167
void SetWidth(int aWidth) override
Set the width of the draw item to aWidth.
Definition: lib_arc.h:134
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:166
void loadFile(const wxString &aFileName, SCH_SCREEN *aScreen)
int GetWidth() const override
Return the width of the draw item.
Definition: lib_bezier.h:102
#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 ...
void Reserve(size_t aCount)
Definition: lib_bezier.h:66
#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:65
std::string EscapedUTF8(const wxString &aString)
Function EscapedUTF8 returns an 8 bit UTF8 string given aString in unicode form.
Definition: string.cpp:214
bool IsRoot() const override
For symbols having aliases, IsRoot() indicates the principal item.
COLOR4D GetDefaultColor() const
Definition: sch_line.cpp:213
#define EESCHEMA_VERSION
Definition: general.h:40
int m_orientation
Pin orientation (Up, Down, Left, Right)
Definition: lib_pin.h:77
SCH_SHEET * loadSheet(FILE_LINE_READER &aReader)
timestamp_t GetNewTimeStamp()
Definition: common.cpp:212
void SetName(const wxString &aName)
#define IS_CHANGED
std::function passed to nested users by ref, avoids copying std::function
Definition: base_struct.h:110
bool ShowPinNumbers()
bool IsPortrait() const
Definition: page_info.h:121
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
wxString m_number
Definition: lib_pin.h:83
LIB_FIELD & GetReferenceField()
Return reference to the reference designator field.
bool isBuffering(const PROPERTIES *aProperties)
void SetEnd(const wxPoint &aPoint)
Definition: lib_arc.h:154
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
BITMAP_BASE * GetImage()
Definition: sch_bitmap.h:65
void SetWidth(int aWidth) override
Set the width of the draw item to aWidth.
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:510
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_junction.h:103
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:216
int GetId() const
Definition: lib_field.h:138
void Reserve(size_t aPointCount)
Definition: lib_polyline.h:65
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:89
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
Definition: page_info.h:54
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:143
LIB_TEXT * loadText(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:207
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:251
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 SetRadius(int aRadius)
Definition: lib_circle.h:101
void Empty()
Definition: eda_text.h:244
Define a library symbol object.
void SetCompany(const wxString &aCompany)
Definition: title_block.h:94
#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:123
wxString GetText(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:33
#define THROW_IO_ERROR(msg)
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 AddPoint(const wxPoint &aPoint)
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: sch_screen.h:138
bool IsVisible() const
Return the visibility status of the draw object.
Definition: lib_pin.h:362
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_sheet.h:547
void SetTitle(const wxString &aTitle)
Definition: title_block.h:60
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:137
LIB_ALIAS * removeAlias(LIB_ALIAS *aAlias)
static int GetLineStyleInternalId(const wxString &aStyleName)
Definition: sch_line.cpp:140
int GetLineStyle() const
Definition: sch_line.cpp:269
wxString GetFileName(void) const
Return the filename corresponding to this sheet.
Definition: sch_sheet.cpp:661
void SetDescription(const wxString &aDescription)
double GetScale() const
Definition: bitmap_base.h:84
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:136
int SetLibItemName(const UTF8 &aLibItemName, bool aTestForRev=true)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:206
void SetFillMode(FILL_T aFillMode)
const wxString & GetComment2() const
Definition: title_block.h:122
const char * delims
void SetSecondRadiusAngle(int aAngle)
Definition: lib_arc.h:144
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:194
LIB_PART * GetPart() const
Get the shared LIB_PART.
void SetConvert(int aConvert)
wxPoint GetPosition() const override
Return the current draw object position.
Definition: lib_pin.h:463
int GetUnitCount() const
void SetFileName(const wxString &aFileName)
int m_attributes
Set bit 0 to indicate pin is invisible.
Definition: lib_pin.h:81
bool checkForDuplicates(wxString &aAliasName)
Definitions for the Eeschema program SCH_SCREEN class.
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:204
int GetDefaultWidth() const
Definition: sch_line.cpp:278
void SetUnit(int aUnit)
int GetRadius() const
Definition: lib_circle.h:103
wxFileName GetRealFile() const
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:160
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
wxPoint m_position
Position of the pin.
Definition: lib_pin.h:75
void SetComment2(const wxString &aComment)
Definition: title_block.h:118
const wxString & GetComment1() const
Definition: title_block.h:121
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
see class PGM_BASE
#define SCH_PARSE_ERROR(text, reader, pos)
const wxString & GetName() const override
void SetEnd(const wxPoint &aEnd)
void RemoveAlias(const wxString &aName)
const int fill_tab[3]
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:112
void Append(SCH_ITEM *aItem)
Definition: sch_screen.h:162
bool IsVisible() const
Definition: lib_field.h:166
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:206
void loadHeader(FILE_LINE_READER &aReader, SCH_SCREEN *aScreen)
bool IsVisible() const
Definition: eda_text.h:189
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.
void SetText(const wxString &aText) override
Sets the text item string to aText.
Definition: lib_text.cpp:350
std::vector< LIB_FIELD > LIB_FIELDS
Definition: lib_field.h:259
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
void SetRadius(int aRadius)
Definition: lib_arc.h:136
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:154
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
static const char * PropBuffering
const char* PropBuffering
ELECTRICAL_PINTYPE m_type
Electrical type of the pin. See enum ELECTRICAL_PINTYPE.
Definition: lib_pin.h:80
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:237
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType, bool aLib=false)
Replace illegal LIB_ID item name characters with underscores &#39;_&#39;.
Definition: lib_id.cpp:352
Class FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
SCH_COMPONENT * loadComponent(FILE_LINE_READER &aReader)
int m_Convert
Shape identification for alternate body styles.
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:54
int GetDefaultStyle() const
Definition: sch_line.cpp:251
Class for a wire to bus entry.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
void SetWidth(int aWidth) override
Set the width of the draw item to aWidth.
Definition: lib_circle.h:99
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:126
SCH_LINE * loadWire(FILE_LINE_READER &aReader)
wxString GetLogicalName() const
void SetStart(const wxPoint &aPoint)
Definition: lib_arc.h:150
int GetPenSize() const override
Function GetPenSize virtual pure.
Definition: sch_line.cpp:296
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:119
const wxString & GetType() const
Definition: page_info.h:97
SCH_NO_CONNECT * loadNoConnect(FILE_LINE_READER &aReader)
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:129
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
void SetWidth(int aWidth) override
Set the width of the draw item to aWidth.
Definition: lib_bezier.h:104
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
#define T_COLORA
wxString GetName() const
Definition: sch_sheet.h:267
int GetLength()
Definition: lib_pin.h:301
#define VALUE
void SetBold(bool aBold)
Definition: eda_text.h:185
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:76
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:235
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Implementation of the label properties dialog.
void saveBusEntry(SCH_BUS_ENTRY_BASE *aBusEntry)
void DeleteSymbol(const wxString &aAliasName)
void AddPoint(const wxPoint &aPoint)
Definition: lib_bezier.h:67
static const char * PropPowerSymsOnly
wxSize GetSize()
Definition: sch_sheet.h:281
int GetHeightMils() const
Definition: page_info.h:140
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:207
void GetFields(LIB_FIELDS &aList)
Return a list of fields within 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.