kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #39718
Patch: Extract LIB_PART read/write from SCH_LEGACY_PLUGIN_CACHE
Attached is a patch solely for extracting legacy LIB_PART read/write
code from the SCH_LEGACY_PLUGIN_CACHE into a complementary pair of
classes, as previously described / discussed.
I'm pretty sure I got it right this time, formatting and all... I'm
still getting used to the process.
Cheers,
-Brian
>From 6947fd0c8ba06490c85c286f8d0068df81ec1cc0 Mon Sep 17 00:00:00 2001
From: Brian Henning <lotharyx@xxxxxxxxx>
Date: Wed, 13 Mar 2019 11:25:31 -0400
Subject: [PATCH] Extracts legacy EESCHEMA symbol read/write into two static
classes, LEGACY_PART_READER and LEGACY_PART_WRITER.
---
CMakeLists.txt | 2 +
eeschema/CMakeLists.txt | 1 +
eeschema/legacy_part_serializer.cpp | 1693 +++++++++++++++++++++++++++
eeschema/legacy_part_serializer.h | 86 ++
eeschema/lib_field.h | 3 +-
eeschema/lib_pin.h | 6 +-
eeschema/sch_legacy_plugin.cpp | 1470 +----------------------
eeschema/sch_legacy_plugin.h | 4 +
8 files changed, 1849 insertions(+), 1416 deletions(-)
create mode 100644 eeschema/legacy_part_serializer.cpp
create mode 100644 eeschema/legacy_part_serializer.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8e34f836..3191d36a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -137,6 +137,8 @@ set( CMAKE_POSITION_INDEPENDENT_CODE ON )
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
+# Global setting: Use abi-version 2
+add_definitions(-fabi-version=2)
# CMP0063: CMake < 3.3 does not handle hidden visibility for static libraries,
# and 3.3 is backwards compatible when the minimum version is smaller than 3.3.
diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt
index c56ac2d9c..ba8d267db 100644
--- a/eeschema/CMakeLists.txt
+++ b/eeschema/CMakeLists.txt
@@ -162,6 +162,7 @@ set( EESCHEMA_SRCS
hierarch.cpp
highlight_connection.cpp
hotkeys.cpp
+ legacy_part_serializer.cpp
lib_arc.cpp
lib_bezier.cpp
lib_circle.cpp
diff --git a/eeschema/legacy_part_serializer.cpp b/eeschema/legacy_part_serializer.cpp
new file mode 100644
index 000000000..4e419ab11
--- /dev/null
+++ b/eeschema/legacy_part_serializer.cpp
@@ -0,0 +1,1693 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2016 CERN
+ * Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * @author Wayne Stambaugh <stambaughw@xxxxxxxxx>, Brian Henning <lotharyx@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "legacy_part_serializer.h"
+
+#include <algorithm>
+#include <ctype.h>
+
+#include <core/typeinfo.h>
+#include <draw_graphic_text.h>
+#include <kicad_string.h>
+#include <kiway.h>
+#include <pgm_base.h>
+#include <properties.h>
+#include <richio.h>
+#include <trace_helpers.h>
+#include <wx/filename.h>
+#include <wx/mstream.h>
+#include <wx/tokenzr.h>
+
+#include <class_libentry.h>
+#include <class_library.h>
+#include <confirm.h>
+#include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
+#include <general.h>
+#include <lib_arc.h>
+#include <lib_bezier.h>
+#include <lib_circle.h>
+#include <lib_field.h>
+#include <lib_pin.h>
+#include <lib_polyline.h>
+#include <lib_rectangle.h>
+#include <lib_text.h>
+#include <sch_bitmap.h>
+#include <sch_bus_entry.h>
+#include <sch_component.h>
+#include <sch_junction.h>
+#include <sch_legacy_plugin.h>
+#include <sch_line.h>
+#include <sch_marker.h>
+#include <sch_no_connect.h>
+#include <sch_screen.h>
+#include <sch_sheet.h>
+#include <sch_text.h>
+#include <symbol_lib_table.h> // for PropPowerSymsOnly definintion.
+#include <template_fieldnames.h>
+
+
+// I have tried and tried, and cannot find a definition for MANDATORY_FIELDS ANYWHERE in the entire
+// source tree, nor does it magically appear after #including everything that sch_legachy_plugin.cpp includes.
+// So I am friggin' defining it here, making a completely wild guess as to what its value should be.
+#define MANDATORY_FIELDS 4
+
+/**
+ * \file Most of the code here is shamelessly stolen from sch_legacy_plugin_cache,
+ * because I need it to be accessible from a static context outside that class
+ */
+
+#define SCH_PARSE_ERROR( text, reader, pos ) \
+ THROW_PARSE_ERROR( \
+ text, reader.GetSource(), reader.Line(), reader.LineNumber(), pos - reader.Line() )
+
+
+// Tokens to read/save graphic lines style
+#define T_STYLE "style"
+#define T_COLOR "rgb" // cannot be modifed (used by wxWidgets)
+#define T_COLORA "rgba" // cannot be modifed (used by wxWidgets)
+#define T_WIDTH "width"
+
+
+static bool is_eol( char c )
+{
+ // The default file eol character used internally by KiCad.
+ // |
+ // | Possible eol if someone edited the file by hand on certain platforms.
+ // | |
+ // | | May have gone past eol with strtok().
+ // | | |
+ if( c == '\n' || c == '\r' || c == 0 )
+ return true;
+
+ return false;
+}
+
+
+/**
+ * Compare \a aString to the string starting at \a aLine and advances the character point to
+ * the end of \a String and returns the new pointer position in \a aOutput if it is not NULL.
+ *
+ * @param aString - A pointer to the string to compare.
+ * @param aLine - A pointer to string to begin the comparison.
+ * @param aOutput - A pointer to a string pointer to the end of the comparison if not NULL.
+ * @return true if \a aString was found starting at \a aLine. Otherwise false.
+ */
+static bool strCompare( const char* aString, const char* aLine, const char** aOutput = NULL )
+{
+ size_t len = strlen( aString );
+ bool retv = ( strncasecmp( aLine, aString, len ) == 0 )
+ && ( isspace( aLine[len] ) || aLine[len] == 0 );
+
+ if( retv && aOutput )
+ {
+ const char* tmp = aLine;
+
+ // Move past the end of the token.
+ tmp += len;
+
+ // Move to the beginning of the next token.
+ while( *tmp && isspace( *tmp ) )
+ tmp++;
+
+ *aOutput = tmp;
+ }
+
+ return retv;
+}
+
+
+/**
+ * Parse an ASCII integer string with possible leading whitespace into
+ * an integer and updates the pointer at \a aOutput if it is not NULL, just
+ * like "man strtol()".
+ *
+ * @param aReader - The line reader used to generate exception throw information.
+ * @param aLine - A pointer the current position in a string.
+ * @param aOutput - The pointer to a string pointer to copy the string pointer position when
+ * the parsing is complete.
+ * @return A valid integer value.
+ * @throw An #IO_ERROR on an unexpected end of line.
+ * @throw A #PARSE_ERROR if the parsed token is not a valid integer.
+ */
+static int parseInt( LINE_READER& aReader, const char* aLine, const char** aOutput = NULL )
+{
+ if( !*aLine )
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
+
+ // Clear errno before calling strtol() in case some other crt call set it.
+ errno = 0;
+
+ long retv = strtol( aLine, (char**) aOutput, 10 );
+
+ // Make sure no error occurred when calling strtol().
+ if( errno == ERANGE )
+ SCH_PARSE_ERROR( "invalid integer value", aReader, aLine );
+
+ // strtol does not strip off whitespace before the next token.
+ if( aOutput )
+ {
+ const char* next = *aOutput;
+
+ while( *next && isspace( *next ) )
+ next++;
+
+ *aOutput = next;
+ }
+
+ return (int) retv;
+}
+
+
+/**
+ * Parse a single ASCII character and updates the pointer at \a aOutput if it is not NULL.
+ *
+ * @param aReader - The line reader used to generate exception throw information.
+ * @param aCurrentToken - A pointer the current position in a string.
+ * @param aNextToken - The pointer to a string pointer to copy the string pointer position when
+ * the parsing is complete.
+ * @return A valid ASCII character.
+ * @throw IO_ERROR on an unexpected end of line.
+ * @throw PARSE_ERROR if the parsed token is not a a single character token.
+ */
+static char parseChar(
+ LINE_READER& aReader, const char* aCurrentToken, const char** aNextToken = NULL )
+{
+ while( *aCurrentToken && isspace( *aCurrentToken ) )
+ aCurrentToken++;
+
+ if( !*aCurrentToken )
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
+
+ if( !isspace( *( aCurrentToken + 1 ) ) )
+ SCH_PARSE_ERROR( "expected single character token", aReader, aCurrentToken );
+
+ if( aNextToken )
+ {
+ const char* next = aCurrentToken + 2;
+
+ while( *next && isspace( *next ) )
+ next++;
+
+ *aNextToken = next;
+ }
+
+ return *aCurrentToken;
+}
+
+
+/**
+ * Parse an unquoted utf8 string and updates the pointer at \a aOutput if it is not NULL.
+ *
+ * The parsed string must be a continuous string with no white space.
+ *
+ * @param aString - A reference to the parsed string.
+ * @param aReader - The line reader used to generate exception throw information.
+ * @param aCurrentToken - A pointer the current position in a string.
+ * @param aNextToken - The pointer to a string pointer to copy the string pointer position when
+ * the parsing is complete.
+ * @param aCanBeEmpty - True if the parsed string is optional. False if it is mandatory.
+ * @throw IO_ERROR on an unexpected end of line.
+ * @throw PARSE_ERROR if the \a aCanBeEmpty is false and no string was parsed.
+ */
+static void parseUnquotedString( wxString& aString, LINE_READER& aReader, const char* aCurrentToken,
+ const char** aNextToken = NULL, bool aCanBeEmpty = false )
+{
+ if( !*aCurrentToken )
+ {
+ if( aCanBeEmpty )
+ return;
+ else
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
+ }
+
+ const char* tmp = aCurrentToken;
+
+ while( *tmp && isspace( *tmp ) )
+ tmp++;
+
+ if( !*tmp )
+ {
+ if( aCanBeEmpty )
+ return;
+ else
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
+ }
+
+ std::string utf8;
+
+ while( *tmp && !isspace( *tmp ) )
+ utf8 += *tmp++;
+
+ aString = FROM_UTF8( utf8.c_str() );
+
+ if( aString.IsEmpty() && !aCanBeEmpty )
+ SCH_PARSE_ERROR( _( "expected unquoted string" ), aReader, aCurrentToken );
+
+ if( aNextToken )
+ {
+ const char* next = tmp;
+
+ while( *next && isspace( *next ) )
+ next++;
+
+ *aNextToken = next;
+ }
+}
+
+
+/**
+ * Parse an quoted ASCII utf8 and updates the pointer at \a aOutput if it is not NULL.
+ *
+ * The parsed string must be contained within a single line. There are no multi-line
+ * quoted strings in the legacy schematic file format.
+ *
+ * @param aString - A reference to the parsed string.
+ * @param aReader - The line reader used to generate exception throw information.
+ * @param aCurrentToken - A pointer the current position in a string.
+ * @param aNextToken - The pointer to a string pointer to copy the string pointer position when
+ * the parsing is complete.
+ * @param aCanBeEmpty - True if the parsed string is optional. False if it is mandatory.
+ * @throw IO_ERROR on an unexpected end of line.
+ * @throw PARSE_ERROR if the \a aCanBeEmpty is false and no string was parsed.
+ */
+static void parseQuotedString( wxString& aString, LINE_READER& aReader, const char* aCurrentToken,
+ const char** aNextToken = NULL, bool aCanBeEmpty = false )
+{
+ if( !*aCurrentToken )
+ {
+ if( aCanBeEmpty )
+ return;
+ else
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
+ }
+
+ const char* tmp = aCurrentToken;
+
+ while( *tmp && isspace( *tmp ) )
+ tmp++;
+
+ if( !*tmp )
+ {
+ if( aCanBeEmpty )
+ return;
+ else
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
+ }
+
+ // Verify opening quote.
+ if( *tmp != '"' )
+ SCH_PARSE_ERROR( "expecting opening quote", aReader, aCurrentToken );
+
+ tmp++;
+
+ std::string utf8; // utf8 without escapes and quotes.
+
+ // Fetch everything up to closing quote.
+ while( *tmp )
+ {
+ if( *tmp == '\\' )
+ {
+ tmp++;
+
+ if( !*tmp )
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
+
+ // Do not copy the escape byte if it is followed by \ or "
+ if( *tmp != '"' && *tmp != '\\' )
+ utf8 += '\\';
+
+ utf8 += *tmp;
+ }
+ else if( *tmp == '"' ) // Closing double quote.
+ {
+ break;
+ }
+ else
+ {
+ utf8 += *tmp;
+ }
+
+ tmp++;
+ }
+
+ aString = FROM_UTF8( utf8.c_str() );
+
+ if( aString.IsEmpty() && !aCanBeEmpty )
+ SCH_PARSE_ERROR( "expected quoted string", aReader, aCurrentToken );
+
+ if( *tmp && *tmp != '"' )
+ SCH_PARSE_ERROR( "no closing quote for string found", aReader, tmp );
+
+ // Move past the closing quote.
+ tmp++;
+
+ if( aNextToken )
+ {
+ const char* next = tmp;
+
+ while( *next && *next == ' ' )
+ next++;
+
+ *aNextToken = next;
+ }
+}
+
+FILL_T parseFillMode( LINE_READER& aReader, const char* aLine, const char** aOutput )
+{
+ switch( parseChar( aReader, aLine, aOutput ) )
+ {
+ case 'F': return FILLED_SHAPE;
+ case 'f': return FILLED_WITH_BG_BODYCOLOR;
+ case 'N': return NO_FILL;
+ default: SCH_PARSE_ERROR( "invalid fill type, expected f, F, or N", aReader, aLine );
+ }
+}
+
+void LEGACY_PART_READER::ReadPart( LIB_PART* aPart, LINE_READER& aReader, int64_t aVersion )
+{
+ const char* line = aReader.Line();
+
+ if( strCompare( "DEF", line, &line ) )
+ {
+
+ long num;
+ size_t pos = 4; // "DEF" plus the first space.
+ wxString utf8Line = wxString::FromUTF8( line );
+ wxStringTokenizer tokens( utf8Line, " \r\n\t" );
+
+ if( tokens.CountTokens() < 8 )
+ SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
+
+ LIB_PART* part = aPart; // Just rename the variable rather than every reference below...
+
+ wxString name, prefix, tmp;
+
+ name = tokens.GetNextToken();
+ pos += name.size() + 1;
+
+ prefix = tokens.GetNextToken();
+ pos += prefix.size() + 1;
+
+ tmp = tokens.GetNextToken();
+ pos += tmp.size() + 1; // NumOfPins, unused.
+
+ tmp = tokens.GetNextToken(); // Pin name offset.
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin offset", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ part->SetPinNameOffset( (int) num );
+
+ tmp = tokens.GetNextToken(); // Show pin numbers.
+
+ if( !( tmp == "Y" || tmp == "N" ) )
+ THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ part->SetShowPinNumbers( ( tmp == "N" ) ? false : true );
+
+ tmp = tokens.GetNextToken(); // Show pin names.
+
+ if( !( tmp == "Y" || tmp == "N" ) )
+ THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ part->SetShowPinNames( ( tmp == "N" ) ? false : true );
+
+ tmp = tokens.GetNextToken(); // Number of units.
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid unit count", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ part->SetUnitCount( (int) num );
+
+ // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
+ if( part->GetUnitCount() < 1 )
+ part->SetUnitCount( 1 );
+
+ // Copy part name and prefix.
+
+ // The root alias is added to the alias list by SetName() which is called by SetText().
+ if( name.IsEmpty() )
+ {
+ part->SetName( "~" );
+ }
+ else if( name[0] != '~' )
+ {
+ part->SetName( name );
+ }
+ else
+ {
+ part->SetName( name.Right( name.Length() - 1 ) );
+ part->GetValueField().SetVisible( false );
+ }
+
+ // Don't set the library alias, this is determined by the symbol library table.
+ part->SetLibId( LIB_ID( wxEmptyString, part->GetName() ) );
+
+ // There are some code paths in SetText() that do not set the root alias to the
+ // alias list so add it here if it didn't get added by SetText().
+ if( !part->HasAlias( part->GetName() ) )
+ part->AddAlias( part->GetName() );
+
+ LIB_FIELD& reference = part->GetReferenceField();
+
+ if( prefix == "~" )
+ {
+ reference.Empty();
+ reference.SetVisible( false );
+ }
+ else
+ {
+ reference.SetText( prefix );
+ }
+
+ // Version 2.2 had a placeholder 0, and it's fine to treat that 0 as if it
+ // has a real meaning (but we'll preserve the version test to be nice to
+ // the upstream folks)
+ tmp = tokens.GetNextToken();
+ if( aVersion > 0 && aVersion > LIB_VERSION( 2, 2 ) )
+ {
+ if( tmp == "L" )
+ part->LockUnits( true );
+ else if( tmp == "F" || tmp == "0" )
+ part->LockUnits( false );
+ else
+ THROW_PARSE_ERROR( "expected L, F, or 0", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+ }
+
+ pos += tmp.size() + 1;
+
+ // There is the optional power component flag.
+ if( tokens.HasMoreTokens() )
+ {
+ tmp = tokens.GetNextToken();
+
+ if( tmp == "P" )
+ part->SetPower();
+ else if( tmp == "N" )
+ part->SetNormal();
+ else
+ THROW_PARSE_ERROR( "expected P or N", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+ }
+
+ line = aReader.ReadLine();
+
+ // Read lines until "ENDDEF" is found.
+ while( line )
+ {
+ if( *line == '#' ) // Comment
+ ;
+ else if( strCompare( "Ti", line, &line ) ) // Modification date is ignored.
+ continue;
+ else if( strCompare( "ALIAS", line, &line ) ) // Aliases
+ loadAliases( part, aReader );
+ else if( *line == 'F' ) // Fields
+ loadField( part, aReader );
+ else if( strCompare( "DRAW", line, &line ) ) // Drawing objects.
+ loadDrawEntries( part, aReader, aVersion );
+ else if( strCompare( "$FPLIST", line, &line ) ) // Footprint filter list
+ loadFootprintFilters( part, aReader );
+ else if( strCompare( "ENDDEF", line, &line ) ) // End of part description
+ {
+ return; // Successful exit point
+ }
+
+ line = aReader.ReadLine();
+ }
+
+ SCH_PARSE_ERROR( "missing ENDDEF", aReader, line );
+ }
+ else
+ {
+ SCH_PARSE_ERROR( "missing DEF", aReader, line );
+ }
+}
+
+void LEGACY_PART_READER::loadAliases( LIB_PART* aPart, LINE_READER& aReader )
+{
+ wxString newAlias;
+ const char* line = aReader.Line();
+
+ wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
+
+ wxString utf8Line = wxString::FromUTF8( line );
+ wxStringTokenizer tokens( utf8Line, " \r\n\t" );
+
+ // Parse the ALIAS list.
+ while( tokens.HasMoreTokens() )
+ {
+ newAlias = tokens.GetNextToken();
+ aPart->AddAlias( newAlias );
+ }
+}
+
+void LEGACY_PART_READER::loadField( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_RET( *line == 'F', "Invalid field line" );
+
+ int id;
+
+ if( sscanf( line + 1, "%d", &id ) != 1 || id < 0 )
+ SCH_PARSE_ERROR( "invalid field ID", aReader, line + 1 );
+
+ LIB_FIELD* field;
+
+ if( (unsigned) id < MANDATORY_FIELDS )
+ {
+ field = aPart->GetField( id );
+
+ // this will fire only if somebody broke a constructor or editor.
+ // MANDATORY_FIELDS are always present in ram resident components, no
+ // exceptions, and they always have their names set, even fixed fields.
+ wxASSERT( field );
+ }
+ else
+ {
+ field = new LIB_FIELD( aPart, id );
+ aPart->AddDrawItem( field );
+ }
+
+ // Skip to the first double quote.
+ while( *line != '"' && *line != 0 )
+ line++;
+
+ if( *line == 0 )
+ SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, line );
+
+ parseQuotedString( field->m_Text, aReader, line, &line, true );
+
+ // Doctor the *.lib file field which has a "~" in blank fields. New saves will
+ // not save like this.
+ if( field->m_Text.size() == 1 && field->m_Text[0] == '~' )
+ field->m_Text.clear();
+
+ wxPoint pos;
+
+ pos.x = parseInt( aReader, line, &line );
+ pos.y = parseInt( aReader, line, &line );
+ field->SetPosition( pos );
+
+ wxSize textSize;
+
+ textSize.x = textSize.y = parseInt( aReader, line, &line );
+ field->SetTextSize( textSize );
+
+ char textOrient = parseChar( aReader, line, &line );
+
+ if( textOrient == 'H' )
+ field->SetTextAngle( TEXT_ANGLE_HORIZ );
+ else if( textOrient == 'V' )
+ field->SetTextAngle( TEXT_ANGLE_VERT );
+ else
+ SCH_PARSE_ERROR( "invalid field text orientation parameter", aReader, line );
+
+ char textVisible = parseChar( aReader, line, &line );
+
+ if( textVisible == 'V' )
+ field->SetVisible( true );
+ else if( textVisible == 'I' )
+ field->SetVisible( false );
+ else
+ SCH_PARSE_ERROR( "invalid field text visibility parameter", aReader, line );
+
+ // It may be technically correct to use the library version to determine if the field text
+ // attributes are present. If anyone knows if that is valid and what version that would be,
+ // please change this to test the library version rather than an EOL or the quoted string
+ // of the field name.
+ if( *line != 0 && *line != '"' )
+ {
+ char textHJustify = parseChar( aReader, line, &line );
+
+ if( textHJustify == 'C' )
+ field->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
+ else if( textHJustify == 'L' )
+ field->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
+ else if( textHJustify == 'R' )
+ field->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
+ else
+ SCH_PARSE_ERROR( "invalid field text horizontal justification", aReader, line );
+
+ wxString attributes;
+
+ parseUnquotedString( attributes, aReader, line, &line );
+
+ size_t attrSize = attributes.size();
+
+ if( !( attrSize == 3 || attrSize == 1 ) )
+ SCH_PARSE_ERROR( "invalid field text attributes size", aReader, line );
+
+ switch( (wxChar) attributes[0] )
+ {
+ case 'C': field->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
+ case 'B': field->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
+ case 'T': field->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
+ default: SCH_PARSE_ERROR( "invalid field text vertical justification", aReader, line );
+ }
+
+ if( attrSize == 3 )
+ {
+ wxChar attr_1 = attributes[1];
+ wxChar attr_2 = attributes[2];
+
+ if( attr_1 == 'I' ) // Italic
+ field->SetItalic( true );
+ else if( attr_1 != 'N' ) // No italics is default, check for error.
+ SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
+
+ if( attr_2 == 'B' ) // Bold
+ field->SetBold( true );
+ else if( attr_2 != 'N' ) // No bold is default, check for error.
+ SCH_PARSE_ERROR( "invalid field text bold parameter", aReader, line );
+ }
+ }
+
+ // Fields in RAM must always have names.
+ if( (unsigned) id < MANDATORY_FIELDS )
+ {
+ // Fields in RAM must always have names, because we are trying to get
+ // less dependent on field ids and more dependent on names.
+ // Plus assumptions are made in the field editors.
+ field->m_name = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
+
+ // Ensure the VALUE field = the part name (can be not the case
+ // with malformed libraries: edited by hand, or converted from other tools)
+ if( id == VALUE )
+ field->m_Text = aPart->GetName();
+ }
+ else
+ {
+ parseQuotedString( field->m_name, aReader, line, &line, true ); // Optional.
+ }
+}
+
+void LEGACY_PART_READER::loadDrawEntries( LIB_PART* aPart, LINE_READER& aReader, int64_t aVersion )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_RET( strCompare( "DRAW", line, &line ), "Invalid DRAW section" );
+
+ line = aReader.ReadLine();
+
+ while( line )
+ {
+ if( strCompare( "ENDDRAW", line, &line ) )
+ return;
+
+ switch( line[0] )
+ {
+ case 'A': // Arc
+ aPart->AddDrawItem( loadArc( aPart, aReader ) );
+ break;
+
+ case 'C': // Circle
+ aPart->AddDrawItem( loadCircle( aPart, aReader ) );
+ break;
+
+ case 'T': // Text
+ aPart->AddDrawItem( loadText( aPart, aReader, aVersion ) );
+ break;
+
+ case 'S': // Square
+ aPart->AddDrawItem( loadRectangle( aPart, aReader ) );
+ break;
+
+ case 'X': // Pin Description
+ aPart->AddDrawItem( loadPin( aPart, aReader ) );
+ break;
+
+ case 'P': // Polyline
+ aPart->AddDrawItem( loadPolyLine( aPart, aReader ) );
+ break;
+
+ case 'B': // Bezier Curves
+ aPart->AddDrawItem( loadBezier( aPart, aReader ) );
+ break;
+
+ case '#': // Comment
+ case '\n': // Empty line
+ case '\r':
+ case 0: break;
+
+ default: SCH_PARSE_ERROR( "undefined DRAW entry", aReader, line );
+ }
+
+ line = aReader.ReadLine();
+ }
+
+ SCH_PARSE_ERROR( "file ended prematurely loading component draw element", aReader, line );
+}
+
+void LEGACY_PART_READER::loadFootprintFilters( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_RET( strCompare( "$FPLIST", line, &line ), "Invalid footprint filter list" );
+
+ line = aReader.ReadLine();
+
+ while( line )
+ {
+ if( strCompare( "$ENDFPLIST", line, &line ) )
+ return;
+
+ wxString footprint;
+
+ parseUnquotedString( footprint, aReader, line, &line );
+ aPart->GetFootprints().Add( footprint );
+ line = aReader.ReadLine();
+ }
+
+ SCH_PARSE_ERROR( "file ended prematurely while loading footprint filters", aReader, line );
+}
+
+LIB_ITEM* LEGACY_PART_READER::loadArc( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "A", line, &line ), NULL, "Invalid LIB_ARC definition" );
+
+ LIB_ARC* arc = new LIB_ARC( aPart );
+
+ wxPoint center;
+
+ center.x = parseInt( aReader, line, &line );
+ center.y = parseInt( aReader, line, &line );
+
+ arc->SetPosition( center );
+ arc->SetRadius( parseInt( aReader, line, &line ) );
+
+ int angle1 = parseInt( aReader, line, &line );
+ int angle2 = parseInt( aReader, line, &line );
+
+ NORMALIZE_ANGLE_POS( angle1 );
+ NORMALIZE_ANGLE_POS( angle2 );
+ arc->SetFirstRadiusAngle( angle1 );
+ arc->SetSecondRadiusAngle( angle2 );
+
+ arc->SetUnit( parseInt( aReader, line, &line ) );
+ arc->SetConvert( parseInt( aReader, line, &line ) );
+ arc->SetWidth( parseInt( aReader, line, &line ) );
+
+ // Old libraries (version <= 2.2) do not have always this FILL MODE param
+ // when fill mode is no fill (default mode).
+ if( *line != 0 )
+ arc->SetFillMode( parseFillMode( aReader, line, &line ) );
+
+ // Actual Coordinates of arc ends are read from file
+ if( *line != 0 )
+ {
+ wxPoint arcStart, arcEnd;
+
+ arcStart.x = parseInt( aReader, line, &line );
+ arcStart.y = parseInt( aReader, line, &line );
+ arcEnd.x = parseInt( aReader, line, &line );
+ arcEnd.y = parseInt( aReader, line, &line );
+
+ arc->SetStart( arcStart );
+ arc->SetEnd( arcEnd );
+ }
+ else
+ {
+ // Actual Coordinates of arc ends are not read from file
+ // (old library), calculate them
+ wxPoint arcStart( arc->GetRadius(), 0 );
+ wxPoint arcEnd( arc->GetRadius(), 0 );
+
+ RotatePoint( &arcStart.x, &arcStart.y, -angle1 );
+ arcStart += arc->GetPosition();
+ arc->SetStart( arcStart );
+ RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 );
+ arcEnd += arc->GetPosition();
+ arc->SetEnd( arcEnd );
+ }
+
+ return arc;
+}
+
+
+LIB_ITEM* LEGACY_PART_READER::loadCircle( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "C", line, &line ), NULL, "Invalid LIB_CIRCLE definition" );
+
+ LIB_CIRCLE* circle = new LIB_CIRCLE( aPart );
+
+ wxPoint center;
+
+ center.x = parseInt( aReader, line, &line );
+ center.y = parseInt( aReader, line, &line );
+
+ circle->SetPosition( center );
+ circle->SetRadius( parseInt( aReader, line, &line ) );
+ circle->SetUnit( parseInt( aReader, line, &line ) );
+ circle->SetConvert( parseInt( aReader, line, &line ) );
+ circle->SetWidth( parseInt( aReader, line, &line ) );
+
+ if( *line != 0 )
+ circle->SetFillMode( parseFillMode( aReader, line, &line ) );
+
+ return circle;
+}
+
+
+LIB_ITEM* LEGACY_PART_READER::loadText( LIB_PART* aPart, LINE_READER& aReader, int64_t aVersion )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "T", line, &line ), NULL, "Invalid LIB_TEXT definition" );
+
+ LIB_TEXT* text = new LIB_TEXT( aPart );
+
+ text->SetTextAngle( (double) parseInt( aReader, line, &line ) );
+
+ wxPoint center;
+
+ center.x = parseInt( aReader, line, &line );
+ center.y = parseInt( aReader, line, &line );
+ text->SetPosition( center );
+
+ wxSize size;
+
+ size.x = size.y = parseInt( aReader, line, &line );
+ text->SetTextSize( size );
+ text->SetVisible( !parseInt( aReader, line, &line ) );
+ text->SetUnit( parseInt( aReader, line, &line ) );
+ text->SetConvert( parseInt( aReader, line, &line ) );
+
+ wxString str;
+
+ // If quoted string loading fails, load as not quoted string.
+ if( *line == '"' )
+ parseQuotedString( str, aReader, line, &line );
+ else
+ {
+ parseUnquotedString( str, aReader, line, &line );
+
+ // In old libs, "spaces" are replaced by '~' in unquoted strings:
+ str.Replace( "~", " " );
+ }
+
+ if( !str.IsEmpty() )
+ {
+ // convert two apostrophes back to double quote
+ str.Replace( "''", "\"" );
+ }
+
+ text->SetText( str );
+
+ // Here things are murky and not well defined. At some point it appears the format
+ // was changed to add text properties. However rather than add the token to the end of
+ // the text definition, it was added after the string and no mention if the file
+ // verion was bumped or not so this code make break on very old component libraries.
+ //
+ // Update: apparently even in the latest version this can be different so added a test
+ // for end of line before checking for the text properties.
+ //
+ // BH - See other developer's comment in loadField as to why I think the version test
+ // is superfluous; leaving it in because I'm trying to be as surgical as possible.
+ if( ( aVersion == 0 || aVersion > LIB_VERSION( 2, 0 ) ) && !is_eol( *line ) )
+ {
+ if( strCompare( "Italic", line, &line ) )
+ text->SetItalic( true );
+ else if( !strCompare( "Normal", line, &line ) )
+ SCH_PARSE_ERROR( "invalid text stype, expected 'Normal' or 'Italic'", aReader, line );
+
+ if( parseInt( aReader, line, &line ) > 0 )
+ text->SetBold( true );
+
+ // Some old libaries version > 2.0 do not have these options for text justification:
+ if( !is_eol( *line ) )
+ {
+ switch( parseChar( aReader, line, &line ) )
+ {
+ case 'L': text->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); break;
+ case 'C': text->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER ); break;
+ case 'R': text->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); break;
+ default:
+ SCH_PARSE_ERROR(
+ "invalid horizontal text justication; expected L, C, or R", aReader, line );
+ }
+
+ switch( parseChar( aReader, line, &line ) )
+ {
+ case 'T': text->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
+ case 'C': text->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
+ case 'B': text->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
+ default:
+ SCH_PARSE_ERROR(
+ "invalid vertical text justication; expected T, C, or B", aReader, line );
+ }
+ }
+ }
+
+ return text;
+}
+
+
+LIB_ITEM* LEGACY_PART_READER::loadRectangle( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "S", line, &line ), NULL, "Invalid LIB_RECTANGLE definition" );
+
+ LIB_RECTANGLE* rectangle = new LIB_RECTANGLE( aPart );
+
+ wxPoint pos;
+
+ pos.x = parseInt( aReader, line, &line );
+ pos.y = parseInt( aReader, line, &line );
+ rectangle->SetPosition( pos );
+
+ wxPoint end;
+
+ end.x = parseInt( aReader, line, &line );
+ end.y = parseInt( aReader, line, &line );
+ rectangle->SetEnd( end );
+
+ rectangle->SetUnit( parseInt( aReader, line, &line ) );
+ rectangle->SetConvert( parseInt( aReader, line, &line ) );
+ rectangle->SetWidth( parseInt( aReader, line, &line ) );
+
+ if( *line != 0 )
+ rectangle->SetFillMode( parseFillMode( aReader, line, &line ) );
+
+ return rectangle;
+}
+
+
+LIB_ITEM* LEGACY_PART_READER::loadPin( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "X", line, &line ), NULL, "Invalid LIB_PIN definition" );
+
+ LIB_PIN* pin = new LIB_PIN( aPart );
+
+ size_t pos = 2; // "X" plus ' ' space character.
+ wxString tmp;
+ wxString utf8Line = wxString::FromUTF8( line );
+ wxStringTokenizer tokens( utf8Line, " \r\n\t" );
+
+ if( tokens.CountTokens() < 11 )
+ SCH_PARSE_ERROR( "invalid pin definition", aReader, line );
+
+ pin->m_name = tokens.GetNextToken();
+ pos += pin->m_name.size() + 1;
+ pin->m_number = tokens.GetNextToken();
+ pos += pin->m_number.size() + 1;
+
+ long num;
+ wxPoint position;
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin X coordinate", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ position.x = (int) num;
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin Y coordinate", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ position.y = (int) num;
+ pin->m_position = position;
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin length", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ pin->m_length = (int) num;
+
+
+ tmp = tokens.GetNextToken();
+
+ if( tmp.size() > 1 )
+ THROW_PARSE_ERROR( "invalid pin orientation", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ pin->m_orientation = tmp[0];
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin number text size", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ pin->m_numTextSize = (int) num;
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin name text size", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ pin->m_nameTextSize = (int) num;
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin unit", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ pin->m_Unit = (int) num;
+
+ tmp = tokens.GetNextToken();
+
+ if( !tmp.ToLong( &num ) )
+ THROW_PARSE_ERROR( "invalid pin alternate body type", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ pin->m_Convert = (int) num;
+
+ tmp = tokens.GetNextToken();
+
+ if( tmp.size() != 1 )
+ THROW_PARSE_ERROR( "invalid pin type", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+
+ pos += tmp.size() + 1;
+ char type = tmp[0];
+
+ wxString attributes;
+
+ switch( type )
+ {
+ case 'I': pin->m_type = PIN_INPUT; break;
+ case 'O': pin->m_type = PIN_OUTPUT; break;
+ case 'B': pin->m_type = PIN_BIDI; break;
+ case 'T': pin->m_type = PIN_TRISTATE; break;
+ case 'P': pin->m_type = PIN_PASSIVE; break;
+ case 'U': pin->m_type = PIN_UNSPECIFIED; break;
+ case 'W': pin->m_type = PIN_POWER_IN; break;
+ case 'w': pin->m_type = PIN_POWER_OUT; break;
+ case 'C': pin->m_type = PIN_OPENCOLLECTOR; break;
+ case 'E': pin->m_type = PIN_OPENEMITTER; break;
+ case 'N': pin->m_type = PIN_NC; break;
+ default:
+ THROW_PARSE_ERROR( "unknown pin type", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+ }
+
+ // Optional
+ if( tokens.HasMoreTokens() ) /* Special Symbol defined */
+ {
+ tmp = tokens.GetNextToken();
+
+ enum
+ {
+ INVERTED = 1 << 0,
+ CLOCK = 1 << 1,
+ LOWLEVEL_IN = 1 << 2,
+ LOWLEVEL_OUT = 1 << 3,
+ FALLING_EDGE = 1 << 4,
+ NONLOGIC = 1 << 5
+ };
+
+ int flags = 0;
+
+ for( int j = tmp.size(); j > 0; )
+ {
+ switch( tmp[--j].GetValue() )
+ {
+ case '~': break;
+ case 'N': pin->m_attributes |= PIN_INVISIBLE; break;
+ case 'I': flags |= INVERTED; break;
+ case 'C': flags |= CLOCK; break;
+ case 'L': flags |= LOWLEVEL_IN; break;
+ case 'V': flags |= LOWLEVEL_OUT; break;
+ case 'F': flags |= FALLING_EDGE; break;
+ case 'X': flags |= NONLOGIC; break;
+ default:
+ THROW_PARSE_ERROR( "invalid pin attribut", aReader.GetSource(), aReader.Line(),
+ aReader.LineNumber(), pos );
+ }
+
+ pos += 1;
+ }
+
+ switch( flags )
+ {
+ case 0: pin->m_shape = PINSHAPE_LINE; break;
+ case INVERTED: pin->m_shape = PINSHAPE_INVERTED; break;
+ case CLOCK: pin->m_shape = PINSHAPE_CLOCK; break;
+ case INVERTED | CLOCK: pin->m_shape = PINSHAPE_INVERTED_CLOCK; break;
+ case LOWLEVEL_IN: pin->m_shape = PINSHAPE_INPUT_LOW; break;
+ case LOWLEVEL_IN | CLOCK: pin->m_shape = PINSHAPE_CLOCK_LOW; break;
+ case LOWLEVEL_OUT: pin->m_shape = PINSHAPE_OUTPUT_LOW; break;
+ case FALLING_EDGE: pin->m_shape = PINSHAPE_FALLING_EDGE_CLOCK; break;
+ case NONLOGIC: pin->m_shape = PINSHAPE_NONLOGIC; break;
+ default: SCH_PARSE_ERROR( "pin attributes do not define a valid pin shape", aReader, line );
+ }
+ }
+
+ return pin;
+}
+
+
+LIB_ITEM* LEGACY_PART_READER::loadPolyLine( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "P", line, &line ), NULL, "Invalid LIB_POLYLINE definition" );
+
+ LIB_POLYLINE* polyLine = new LIB_POLYLINE( aPart );
+
+ int points = parseInt( aReader, line, &line );
+ polyLine->SetUnit( parseInt( aReader, line, &line ) );
+ polyLine->SetConvert( parseInt( aReader, line, &line ) );
+ polyLine->SetWidth( parseInt( aReader, line, &line ) );
+ polyLine->Reserve( points );
+
+ wxPoint pt;
+
+ for( int i = 0; i < points; i++ )
+ {
+ pt.x = parseInt( aReader, line, &line );
+ pt.y = parseInt( aReader, line, &line );
+ polyLine->AddPoint( pt );
+ }
+
+ if( *line != 0 )
+ polyLine->SetFillMode( parseFillMode( aReader, line, &line ) );
+
+ return polyLine;
+}
+
+
+LIB_ITEM* LEGACY_PART_READER::loadBezier( LIB_PART* aPart, LINE_READER& aReader )
+{
+ const char* line = aReader.Line();
+
+ wxCHECK_MSG( strCompare( "B", line, &line ), NULL, "Invalid LIB_BEZIER definition" );
+
+ LIB_BEZIER* bezier = new LIB_BEZIER( aPart );
+
+ int points = parseInt( aReader, line, &line );
+ bezier->SetUnit( parseInt( aReader, line, &line ) );
+ bezier->SetConvert( parseInt( aReader, line, &line ) );
+ bezier->SetWidth( parseInt( aReader, line, &line ) );
+
+ wxPoint pt;
+ bezier->Reserve( points );
+
+ for( int i = 0; i < points; i++ )
+ {
+ pt.x = parseInt( aReader, line, &line );
+ pt.y = parseInt( aReader, line, &line );
+ bezier->AddPoint( pt );
+ }
+
+ if( *line != 0 )
+ bezier->SetFillMode( parseFillMode( aReader, line, &line ) );
+
+ return bezier;
+}
+
+/****************************************************************************\
+ * *
+ * Above was reading; below is writing. I'm making this comment block *
+ * very tall so that it's visible in Kate's thumbnail-scrollbar thingy. *
+ * *
+ * Here's a kitty! *
+ * *
+ * ,. ., *
+ * ,: ':. .,. .:' :, *
+ * ,', '.:' ':.' ,', *
+ * : '. ' ' .' : *
+ * ', : ' ' : ,' *
+ * '.' .,:,. .,:,. '.' *
+ * ,: V '. .' V :, *
+ * ,: / ' :, *
+ * ,: :, *
+ * ,: =:= :, *
+ * ,: , : , :, *
+ * :' ',.,' ',.,:' ': *
+ * :' ':WW::' '. *
+ * .:' '::::' ': *
+ * ,: '::::' :, *
+ * :' ':::' ': *
+ * ,: ':'' :. *
+ * .:' '. ',. *
+ * ,:' '' '. *
+ * .:' .', ': *
+ * .:' .'., : *
+ * .: .,'' : *
+ * :: .,'' ,: *
+ * :: .,'',' .:' *
+ * .,::'. .,',' ::::. *
+ * .:' ',. ,:, ,WWWWW, *
+ * :' : :W:' :WWWWWWW, .,. *
+ * : ', WWW WWWWWWWWW '::, *
+ * '. ', WWW :WWWWWWWWW '::, *
+ * '. : WWW :WWWWWWWW' ::: *
+ * '. ,: WWW :WWWWWWW' .::: *
+ * '. .W: WWW :WWWWWW' .,:::' *
+ * '. :WW: WWW :WWWWW' .,,:::::'' *
+ * .,' '':: :W: :WWWWW. .,::::'' *
+ * ,' ''','',',','','''WWWWW::::'' *
+ * ':,,,,,,,': : : : : : :WWWW''' *
+ * *
+ * *
+ * *
+ * *
+ * **************************************************************************/
+
+void LEGACY_PART_WRITER::WritePart( LIB_PART* aSymbol, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( aSymbol, "Invalid LIB_PART pointer." );
+
+ LIB_FIELD& value = aSymbol->GetValueField();
+
+ // First line: it s a comment (component name for readers)
+ aFormatter.Print( 0, "#\n# %s\n#\n", TO_UTF8( value.GetText() ) );
+
+ // Save data
+ aFormatter.Print( 0, "DEF" );
+
+ if( value.IsVisible() )
+ {
+ aFormatter.Print( 0, " %s", TO_UTF8( value.GetText() ) );
+ }
+ else
+ {
+ aFormatter.Print( 0, " ~%s", TO_UTF8( value.GetText() ) );
+ }
+
+ LIB_FIELD& reference = aSymbol->GetReferenceField();
+
+ if( !reference.GetText().IsEmpty() )
+ {
+ aFormatter.Print( 0, " %s", TO_UTF8( reference.GetText() ) );
+ }
+ else
+ {
+ aFormatter.Print( 0, " ~" );
+ }
+
+ aFormatter.Print( 0, " %d %d %c %c %d %c %c\n", 0, aSymbol->GetPinNameOffset(),
+ aSymbol->ShowPinNumbers() ? 'Y' : 'N', aSymbol->ShowPinNames() ? 'Y' : 'N',
+ aSymbol->GetUnitCount(), aSymbol->UnitsLocked() ? 'L' : 'F',
+ aSymbol->IsPower() ? 'P' : 'N' );
+
+ timestamp_t dateModified = aSymbol->GetDateLastEdition();
+
+ if( dateModified != 0 )
+ {
+ int sec = dateModified & 63;
+ int min = ( dateModified >> 6 ) & 63;
+ int hour = ( dateModified >> 12 ) & 31;
+ int day = ( dateModified >> 17 ) & 31;
+ int mon = ( dateModified >> 22 ) & 15;
+ int year = ( dateModified >> 26 ) + 1990;
+
+ aFormatter.Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec );
+ }
+
+ LIB_FIELDS fields;
+ aSymbol->GetFields( fields );
+
+ // Mandatory fields:
+ // may have their own save policy so there is a separate loop for them.
+ // Empty fields are saved, because the user may have set visibility,
+ // size and orientation
+ for( int i = 0; i < MANDATORY_FIELDS; ++i )
+ {
+ saveField( &fields[i], aFormatter );
+ }
+
+ // User defined fields:
+ // may have their own save policy so there is a separate loop for them.
+
+ int fieldId = MANDATORY_FIELDS; // really wish this would go away.
+
+ for( unsigned i = MANDATORY_FIELDS; i < fields.size(); ++i )
+ {
+ // There is no need to save empty fields, i.e. no reason to preserve field
+ // names now that fields names come in dynamically through the template
+ // fieldnames.
+ if( !fields[i].GetText().IsEmpty() )
+ {
+ fields[i].SetId( fieldId++ );
+ saveField( &fields[i], aFormatter );
+ }
+ }
+
+ // Save the alias list: a line starting by "ALIAS". The first alias is the root
+ // and has the same name as the component. In the old library file format this
+ // alias does not get added to the alias list.
+ if( aSymbol->GetAliasCount() > 1 )
+ {
+ wxArrayString aliases = aSymbol->GetAliasNames();
+
+ aFormatter.Print( 0, "ALIAS" );
+
+ for( unsigned i = 1; i < aliases.size(); i++ )
+ {
+ aFormatter.Print( 0, " %s", TO_UTF8( aliases[i] ) );
+ }
+
+ aFormatter.Print( 0, "\n" );
+ }
+
+ wxArrayString footprints = aSymbol->GetFootprints();
+
+ // Write the footprint filter list
+ if( footprints.GetCount() != 0 )
+ {
+ aFormatter.Print( 0, "$FPLIST\n" );
+
+ for( unsigned i = 0; i < footprints.GetCount(); i++ )
+ {
+ aFormatter.Print( 0, " %s\n", TO_UTF8( footprints[i] ) );
+ }
+
+ aFormatter.Print( 0, "$ENDFPLIST\n" );
+ }
+
+ // Save graphics items (including pins)
+ if( !aSymbol->GetDrawItems().empty() )
+ {
+ // Sort the draw items in order to editing a file editing by hand.
+ aSymbol->GetDrawItems().sort();
+
+ aFormatter.Print( 0, "DRAW\n" );
+
+ for( LIB_ITEM& item : aSymbol->GetDrawItems() )
+ {
+ switch( item.Type() )
+ {
+ case LIB_FIELD_T: // Fields have already been saved above.
+ continue;
+
+ case LIB_ARC_T: saveArc( &item, aFormatter ); break;
+
+ case LIB_BEZIER_T: saveBezier( &item, aFormatter ); break;
+
+ case LIB_CIRCLE_T: saveCircle( &item, aFormatter ); break;
+
+ case LIB_PIN_T: savePin( &item, aFormatter ); break;
+
+ case LIB_POLYLINE_T: savePolyLine( &item, aFormatter ); break;
+
+ case LIB_RECTANGLE_T: saveRectangle( &item, aFormatter ); break;
+
+ case LIB_TEXT_T: saveText( &item, aFormatter ); break;
+
+ default:;
+ }
+ }
+
+ aFormatter.Print( 0, "ENDDRAW\n" );
+ }
+
+ aFormatter.Print( 0, "ENDDEF\n" );
+}
+
+
+void LEGACY_PART_WRITER::saveField( LIB_FIELD* aField, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( aField && aField->Type() == LIB_FIELD_T, "Invalid LIB_FIELD object." );
+
+ int hjustify, vjustify;
+ int id = aField->GetId();
+ wxString text = aField->m_Text;
+
+ hjustify = 'C';
+
+ if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
+ hjustify = 'L';
+ else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
+ hjustify = 'R';
+
+ vjustify = 'C';
+
+ if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
+ vjustify = 'B';
+ else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
+ vjustify = 'T';
+
+ aFormatter.Print( 0, "F%d %s %d %d %d %c %c %c %c%c%c", id,
+ EscapedUTF8( text ).c_str(), // wraps in quotes
+ aField->GetTextPos().x, aField->GetTextPos().y, aField->GetTextWidth(),
+ aField->GetTextAngle() == 0 ? 'H' : 'V', aField->IsVisible() ? 'V' : 'I', hjustify,
+ vjustify, aField->IsItalic() ? 'I' : 'N', aField->IsBold() ? 'B' : 'N' );
+
+ /* Save field name, if necessary
+ * Field name is saved only if it is not the default name.
+ * Just because default name depends on the language and can change from
+ * a country to another
+ */
+ wxString defName = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
+
+ if( id >= FIELD1 && !aField->m_name.IsEmpty() && aField->m_name != defName )
+ aFormatter.Print( 0, " %s", EscapedUTF8( aField->m_name ).c_str() );
+
+ aFormatter.Print( 0, "\n" );
+}
+
+
+void LEGACY_PART_WRITER::saveArc( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_ARC_T, "Invalid LIB_ARC object." );
+
+ LIB_ARC* aArc = (LIB_ARC*) anItem;
+
+ int x1 = aArc->GetFirstRadiusAngle();
+
+ if( x1 > 1800 )
+ x1 -= 3600;
+
+ int x2 = aArc->GetSecondRadiusAngle();
+
+ if( x2 > 1800 )
+ x2 -= 3600;
+
+ aFormatter.Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n", aArc->GetPosition().x,
+ aArc->GetPosition().y, aArc->GetRadius(), x1, x2, aArc->GetUnit(), aArc->GetConvert(),
+ aArc->GetWidth(), fill_tab[aArc->GetFillMode()], aArc->GetStart().x, aArc->GetStart().y,
+ aArc->GetEnd().x, aArc->GetEnd().y );
+}
+
+
+void LEGACY_PART_WRITER::saveCircle( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_CIRCLE_T, "Invalid LIB_CIRCLE object." );
+
+ LIB_CIRCLE* aCircle = (LIB_CIRCLE*) anItem;
+
+ aFormatter.Print( 0, "C %d %d %d %d %d %d %c\n", aCircle->GetPosition().x,
+ aCircle->GetPosition().y, aCircle->GetRadius(), aCircle->GetUnit(),
+ aCircle->GetConvert(), aCircle->GetWidth(), fill_tab[aCircle->GetFillMode()] );
+}
+
+
+void LEGACY_PART_WRITER::saveText( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_TEXT_T, "Invalid LIB_TEXT object." );
+
+ LIB_TEXT* aText = (LIB_TEXT*) anItem;
+
+ wxString text = aText->GetText();
+
+ if( text.Contains( wxT( " " ) ) || text.Contains( wxT( "~" ) ) || text.Contains( wxT( "\"" ) ) )
+ {
+ // convert double quote to similar-looking two apostrophes
+ text.Replace( wxT( "\"" ), wxT( "''" ) );
+ text = wxT( "\"" ) + text + wxT( "\"" );
+ }
+
+ aFormatter.Print( 0, "T %g %d %d %d %d %d %d %s", aText->GetTextAngle(), aText->GetTextPos().x,
+ aText->GetTextPos().y, aText->GetTextWidth(), !aText->IsVisible(), aText->GetUnit(),
+ aText->GetConvert(), TO_UTF8( text ) );
+
+ aFormatter.Print( 0, " %s %d", aText->IsItalic() ? "Italic" : "Normal", aText->IsBold() );
+
+ char hjustify = 'C';
+
+ if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
+ hjustify = 'L';
+ else if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
+ hjustify = 'R';
+
+ char vjustify = 'C';
+
+ if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
+ vjustify = 'B';
+ else if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
+ vjustify = 'T';
+
+ aFormatter.Print( 0, " %c %c\n", hjustify, vjustify );
+}
+
+
+void LEGACY_PART_WRITER::saveRectangle( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_RECTANGLE_T, "Invalid LIB_RECTANGLE object." );
+
+ LIB_RECTANGLE* aRectangle = (LIB_RECTANGLE*) anItem;
+
+ aFormatter.Print( 0, "S %d %d %d %d %d %d %d %c\n", aRectangle->GetPosition().x,
+ aRectangle->GetPosition().y, aRectangle->GetEnd().x, aRectangle->GetEnd().y,
+ aRectangle->GetUnit(), aRectangle->GetConvert(), aRectangle->GetWidth(),
+ fill_tab[aRectangle->GetFillMode()] );
+}
+
+
+void LEGACY_PART_WRITER::savePin( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_PIN_T, "Invalid LIB_PIN object." );
+
+ LIB_PIN* aPin = (LIB_PIN*) anItem;
+
+ int Etype;
+
+ switch( aPin->GetType() )
+ {
+ default:
+ case PIN_INPUT: Etype = 'I'; break;
+
+ case PIN_OUTPUT: Etype = 'O'; break;
+
+ case PIN_BIDI: Etype = 'B'; break;
+
+ case PIN_TRISTATE: Etype = 'T'; break;
+
+ case PIN_PASSIVE: Etype = 'P'; break;
+
+ case PIN_UNSPECIFIED: Etype = 'U'; break;
+
+ case PIN_POWER_IN: Etype = 'W'; break;
+
+ case PIN_POWER_OUT: Etype = 'w'; break;
+
+ case PIN_OPENCOLLECTOR: Etype = 'C'; break;
+
+ case PIN_OPENEMITTER: Etype = 'E'; break;
+
+ case PIN_NC: Etype = 'N'; break;
+ }
+
+ if( !aPin->GetName().IsEmpty() )
+ aFormatter.Print( 0, "X %s", TO_UTF8( aPin->GetName() ) );
+ else
+ aFormatter.Print( 0, "X ~" );
+
+ aFormatter.Print( 0, " %s %d %d %d %c %d %d %d %d %c",
+ aPin->GetNumber().IsEmpty() ? "~" : TO_UTF8( aPin->GetNumber() ), aPin->GetPosition().x,
+ aPin->GetPosition().y, (int) aPin->GetLength(), (int) aPin->GetOrientation(),
+ aPin->GetNumberTextSize(), aPin->GetNameTextSize(), aPin->GetUnit(), aPin->GetConvert(),
+ Etype );
+
+ if( aPin->GetShape() || !aPin->IsVisible() )
+ aFormatter.Print( 0, " " );
+
+ if( !aPin->IsVisible() )
+ aFormatter.Print( 0, "N" );
+
+ switch( aPin->GetShape() )
+ {
+ case PINSHAPE_LINE: break;
+
+ case PINSHAPE_INVERTED: aFormatter.Print( 0, "I" ); break;
+
+ case PINSHAPE_CLOCK: aFormatter.Print( 0, "C" ); break;
+
+ case PINSHAPE_INVERTED_CLOCK: aFormatter.Print( 0, "IC" ); break;
+
+ case PINSHAPE_INPUT_LOW: aFormatter.Print( 0, "L" ); break;
+
+ case PINSHAPE_CLOCK_LOW: aFormatter.Print( 0, "CL" ); break;
+
+ case PINSHAPE_OUTPUT_LOW: aFormatter.Print( 0, "V" ); break;
+
+ case PINSHAPE_FALLING_EDGE_CLOCK: aFormatter.Print( 0, "F" ); break;
+
+ case PINSHAPE_NONLOGIC: aFormatter.Print( 0, "X" ); break;
+
+ default: assert( !"Invalid pin shape" );
+ }
+
+ aFormatter.Print( 0, "\n" );
+
+ aPin->ClearFlags( IS_CHANGED );
+}
+
+
+void LEGACY_PART_WRITER::savePolyLine( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_POLYLINE_T, "Invalid LIB_POLYLINE object." );
+
+ LIB_POLYLINE* aPolyLine = (LIB_POLYLINE*) anItem;
+
+ int ccount = aPolyLine->GetCornerCount();
+
+ aFormatter.Print( 0, "P %d %d %d %d", ccount, aPolyLine->GetUnit(), aPolyLine->GetConvert(),
+ aPolyLine->GetWidth() );
+
+ for( const auto& pt : aPolyLine->GetPolyPoints() )
+ {
+ aFormatter.Print( 0, " %d %d", pt.x, pt.y );
+ }
+
+ aFormatter.Print( 0, " %c\n", fill_tab[aPolyLine->GetFillMode()] );
+}
+
+
+void LEGACY_PART_WRITER::saveBezier( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter )
+{
+ wxCHECK_RET( anItem && anItem->Type() == LIB_BEZIER_T, "Invalid LIB_BEZIER object." );
+
+ LIB_BEZIER* aBezier = (LIB_BEZIER*) anItem;
+
+ aFormatter.Print( 0, "B %u %d %d %d", (unsigned) aBezier->GetPoints().size(),
+ aBezier->GetUnit(), aBezier->GetConvert(), aBezier->GetWidth() );
+
+ for( const auto& pt : aBezier->GetPoints() )
+ aFormatter.Print( 0, " %d %d", pt.x, pt.y );
+
+ aFormatter.Print( 0, " %c\n", fill_tab[aBezier->GetFillMode()] );
+}
diff --git a/eeschema/legacy_part_serializer.h b/eeschema/legacy_part_serializer.h
new file mode 100644
index 000000000..47f2a6d53
--- /dev/null
+++ b/eeschema/legacy_part_serializer.h
@@ -0,0 +1,86 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2016 CERN
+ * Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * @author Wayne Stambaugh <stambaughw@xxxxxxxxx>, Brian Henning <lotharyx@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LEGACY_PART_SERIALIZER_H
+#define LEGACY_PART_SERIALIZER_H
+
+#include <stdint.h>
+
+class LIB_ITEM;
+class LIB_PART;
+class LIB_FIELD;
+class LINE_READER;
+class OUTPUTFORMATTER;
+
+/**
+ * Extracted code from SCH_LEGACY_PLUGIN_CACHE presenting legacy
+ * LIB_PART read to whomever wants it.
+ */
+class LEGACY_PART_READER
+{
+public:
+ /**
+ * Reads a legacy LIB_PART descriptor from aReader to configure aPart
+ * with optional version rules
+ */
+ static void ReadPart( LIB_PART* aPart, LINE_READER& aReader, int64_t aVersion = 0 );
+
+private:
+ static void loadAliases( LIB_PART* aPart, LINE_READER& aReader );
+ static void loadField( LIB_PART* aPart, LINE_READER& aReader );
+ static void loadDrawEntries( LIB_PART* aPart, LINE_READER& aReader, int64_t aVersion );
+ static void loadFootprintFilters( LIB_PART* aPart, LINE_READER& aReader );
+
+ static LIB_ITEM* loadArc( LIB_PART* aPart, LINE_READER& aReader );
+ static LIB_ITEM* loadCircle( LIB_PART* aPart, LINE_READER& aReader );
+ static LIB_ITEM* loadText( LIB_PART* aPart, LINE_READER& aReader, int64_t aVersion );
+ static LIB_ITEM* loadRectangle( LIB_PART* aPart, LINE_READER& aReader );
+ static LIB_ITEM* loadPin( LIB_PART* aPart, LINE_READER& aReader );
+ static LIB_ITEM* loadPolyLine( LIB_PART* aPart, LINE_READER& aReader );
+ static LIB_ITEM* loadBezier( LIB_PART* aPart, LINE_READER& aReader );
+};
+
+/**
+ * Extracted code from SCH_LEGACY_PLUGIN_CACHE presenting legacy
+ * LIB_PART write to whomever wants it.
+ */
+class LEGACY_PART_WRITER
+{
+public:
+ /**
+ * Writes a legacy LIB_PART descriptor for aPart to aFormatter
+ */
+ static void WritePart( LIB_PART* aSymbol, OUTPUTFORMATTER& aFormatter );
+
+private:
+ static void saveField( LIB_FIELD* aField, OUTPUTFORMATTER& aFormatter );
+
+ static void saveArc( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+ static void saveCircle( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+ static void saveText( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+ static void saveRectangle( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+ static void savePin( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+ static void savePolyLine( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+ static void saveBezier( LIB_ITEM* anItem, OUTPUTFORMATTER& aFormatter );
+};
+
+#endif // LEGACY_PART_SERIALIZER_H
diff --git a/eeschema/lib_field.h b/eeschema/lib_field.h
index 4c097b522..cd6c27a56 100644
--- a/eeschema/lib_field.h
+++ b/eeschema/lib_field.h
@@ -83,7 +83,8 @@ class LIB_FIELD : public LIB_ITEM, public EDA_TEXT
*/
void CalcEdit( const wxPoint& aPosition ) override;
- friend class SCH_LEGACY_PLUGIN_CACHE; // Required to access m_name.
+ friend class LEGACY_PART_READER; // Required to access m_name.
+ friend class LEGACY_PART_WRITER;
public:
diff --git a/eeschema/lib_pin.h b/eeschema/lib_pin.h
index 931e2f76a..8aecd5fce 100644
--- a/eeschema/lib_pin.h
+++ b/eeschema/lib_pin.h
@@ -69,8 +69,10 @@ class LIB_PIN : public LIB_ITEM
{
// Unlike most of the other LIB_ITEMs, the SetXXX() routines on LIB_PINs are at the UI
// level, performing additional pin checking, multi-pin editing, and setting the modified
- // flag. So the LEGACY_PLUGIN_CACHE needs direct access to the member variables.
- friend class SCH_LEGACY_PLUGIN_CACHE;
+ // flag. So LEGACY_PART_READER and LEGACY_PART_WRITER need direct access to the member
+ // variables.
+ friend class LEGACY_PART_READER;
+ friend class LEGACY_PART_WRITER;
wxPoint m_position; ///< Position of the pin.
int m_length; ///< Length of the pin.
diff --git a/eeschema/sch_legacy_plugin.cpp b/eeschema/sch_legacy_plugin.cpp
index 6a54953b3..a4a860a75 100644
--- a/eeschema/sch_legacy_plugin.cpp
+++ b/eeschema/sch_legacy_plugin.cpp
@@ -62,6 +62,8 @@
#include <symbol_lib_table.h> // for PropPowerSymsOnly definintion.
#include <confirm.h>
+#include <legacy_part_serializer.h>
+
// Must be the first line of part library document (.dcm) files.
#define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
@@ -478,43 +480,14 @@ class SCH_LEGACY_PLUGIN_CACHE
LIB_PART* loadPart( FILE_LINE_READER& aReader );
void loadHeader( FILE_LINE_READER& aReader );
- void loadAliases( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- void loadField( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- void loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader );
- void loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader );
void loadDocs();
- LIB_ARC* loadArc( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- LIB_CIRCLE* loadCircle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- LIB_TEXT* loadText( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- LIB_RECTANGLE* loadRectangle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- LIB_PIN* loadPin( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- LIB_POLYLINE* loadPolyLine( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
- LIB_BEZIER* loadBezier( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-
- FILL_T parseFillMode( FILE_LINE_READER& aReader, const char* aLine,
- const char** aOutput );
+
bool checkForDuplicates( wxString& aAliasName );
LIB_ALIAS* removeAlias( LIB_ALIAS* aAlias );
void saveDocFile();
void saveSymbol( LIB_PART* aSymbol,
std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void saveArc( LIB_ARC* aArc, std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void saveBezier( LIB_BEZIER* aBezier,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void saveCircle( LIB_CIRCLE* aCircle,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void saveField( LIB_FIELD* aField,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void savePin( LIB_PIN* aPin, std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void savePolyLine( LIB_POLYLINE* aPolyLine,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void saveRectangle( LIB_RECTANGLE* aRectangle,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
- void saveText( LIB_TEXT* aText,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter );
friend SCH_LEGACY_PLUGIN;
@@ -2574,208 +2547,52 @@ LIB_PART* SCH_LEGACY_PLUGIN_CACHE::loadPart( FILE_LINE_READER& aReader )
wxCHECK( strCompare( "DEF", line, &line ), NULL );
- long num;
- size_t pos = 4; // "DEF" plus the first space.
- wxString utf8Line = wxString::FromUTF8( line );
- wxStringTokenizer tokens( utf8Line, " \r\n\t" );
-
- if( tokens.CountTokens() < 8 )
- SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
-
- // Read DEF line:
std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) );
- wxString name, prefix, tmp;
-
- name = tokens.GetNextToken();
- pos += name.size() + 1;
-
- prefix = tokens.GetNextToken();
- pos += prefix.size() + 1;
-
- tmp = tokens.GetNextToken();
- pos += tmp.size() + 1; // NumOfPins, unused.
-
- tmp = tokens.GetNextToken(); // Pin name offset.
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin offset", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- part->SetPinNameOffset( (int)num );
-
- tmp = tokens.GetNextToken(); // Show pin numbers.
-
- if( !( tmp == "Y" || tmp == "N") )
- THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- part->SetShowPinNumbers( ( tmp == "N" ) ? false : true );
-
- tmp = tokens.GetNextToken(); // Show pin names.
-
- if( !( tmp == "Y" || tmp == "N") )
- THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- part->SetShowPinNames( ( tmp == "N" ) ? false : true );
-
- tmp = tokens.GetNextToken(); // Number of units.
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid unit count", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- part->SetUnitCount( (int)num );
-
- // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
- if( part->GetUnitCount() < 1 )
- part->SetUnitCount( 1 );
-
- // Copy part name and prefix.
-
- // The root alias is added to the alias list by SetName() which is called by SetText().
- if( name.IsEmpty() )
- {
- part->SetName( "~" );
- }
- else if( name[0] != '~' )
- {
- part->SetName( name );
- }
- else
- {
- part->SetName( name.Right( name.Length() - 1 ) );
- part->GetValueField().SetVisible( false );
- }
-
- // Don't set the library alias, this is determined by the symbol library table.
- part->SetLibId( LIB_ID( wxEmptyString, part->GetName() ) );
+ LEGACY_PART_READER::ReadPart(
+ part.get(), aReader, LIB_VERSION( m_versionMajor, m_versionMinor ) );
- // There are some code paths in SetText() that do not set the root alias to the
- // alias list so add it here if it didn't get added by SetText().
- if( !part->HasAlias( part->GetName() ) )
- part->AddAlias( part->GetName() );
- LIB_FIELD& reference = part->GetReferenceField();
-
- if( prefix == "~" )
- {
- reference.Empty();
- reference.SetVisible( false );
- }
- else
- {
- reference.SetText( prefix );
- }
-
- // In version 2.2 and earlier, this parameter was a '0' which was just a place holder.
- // The was no concept of interchangeable multiple unit symbols.
- if( LIB_VERSION( m_versionMajor, m_versionMinor ) <= LIB_VERSION( 2, 2 ) )
- {
- // Nothing needs to be set since the default setting for symbols with multiple
- // units were never interchangeable. Just parse the 0 an move on.
- tmp = tokens.GetNextToken();
- pos += tmp.size() + 1;
- }
- else
+ // Add aliases
+ for( size_t ii = 0; ii < part->GetAliasCount(); ++ii )
{
- tmp = tokens.GetNextToken();
-
- if( tmp == "L" )
- part->LockUnits( true );
- else if( tmp == "F" || tmp == "0" )
- part->LockUnits( false );
- else
- THROW_PARSE_ERROR( "expected L, F, or 0", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
+ LIB_ALIAS* alias = part->GetAlias( ii );
+ const wxString& aliasName = alias->GetName();
+ auto it = m_aliases.find( aliasName );
- pos += tmp.size() + 1;
- }
+ if( it != m_aliases.end() )
+ {
+ // Find a new name for the alias
+ wxString newName;
+ int idx = 0;
+ LIB_ALIAS_MAP::const_iterator jt;
- // There is the optional power component flag.
- if( tokens.HasMoreTokens() )
- {
- tmp = tokens.GetNextToken();
+ do
+ {
+ newName = wxString::Format( "%s_%d", aliasName, idx );
+ jt = m_aliases.find( newName );
+ ++idx;
+ } while( jt != m_aliases.end() );
+
+ wxLogWarning(
+ "Symbol name conflict in library:\n%s\n"
+ "'%s' has been renamed to '%s'",
+ m_fileName, aliasName, newName );
+
+ if( alias->IsRoot() )
+ part->SetName( newName );
+ else
+ alias->SetName( newName );
- if( tmp == "P" )
- part->SetPower();
- else if( tmp == "N" )
- part->SetNormal();
+ m_aliases[newName] = alias;
+ }
else
- THROW_PARSE_ERROR( "expected P or N", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
- }
-
- line = aReader.ReadLine();
-
- // Read lines until "ENDDEF" is found.
- while( line )
- {
- if( *line == '#' ) // Comment
- ;
- else if( strCompare( "Ti", line, &line ) ) // Modification date is ignored.
- continue;
- else if( strCompare( "ALIAS", line, &line ) ) // Aliases
- loadAliases( part, aReader );
- else if( *line == 'F' ) // Fields
- loadField( part, aReader );
- else if( strCompare( "DRAW", line, &line ) ) // Drawing objects.
- loadDrawEntries( part, aReader );
- else if( strCompare( "$FPLIST", line, &line ) ) // Footprint filter list
- loadFootprintFilters( part, aReader );
- else if( strCompare( "ENDDEF", line, &line ) ) // End of part description
{
- // Add aliases
- for( size_t ii = 0; ii < part->GetAliasCount(); ++ii )
- {
- LIB_ALIAS* alias = part->GetAlias( ii );
- const wxString& aliasName = alias->GetName();
- auto it = m_aliases.find( aliasName );
-
- if( it != m_aliases.end() )
- {
- // Find a new name for the alias
- wxString newName;
- int idx = 0;
- LIB_ALIAS_MAP::const_iterator jt;
-
- do
- {
- newName = wxString::Format( "%s_%d", aliasName, idx );
- jt = m_aliases.find( newName );
- ++idx;
- }
- while( jt != m_aliases.end() );
-
- wxLogWarning( "Symbol name conflict in library:\n%s\n"
- "'%s' has been renamed to '%s'",
- m_fileName, aliasName, newName );
-
- if( alias->IsRoot() )
- part->SetName( newName );
- else
- alias->SetName( newName );
-
- m_aliases[newName] = alias;
- }
- else
- {
- m_aliases[aliasName] = alias;
- }
- }
-
- return part.release();
+ m_aliases[aliasName] = alias;
}
-
- line = aReader.ReadLine();
}
- SCH_PARSE_ERROR( "missing ENDDEF", aReader, line );
+ return part.release();
}
@@ -2805,1216 +2622,43 @@ bool SCH_LEGACY_PLUGIN_CACHE::checkForDuplicates( wxString& aAliasName )
}
-void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- wxString newAlias;
- const char* line = aReader.Line();
-
- wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
-
- wxString utf8Line = wxString::FromUTF8( line );
- wxStringTokenizer tokens( utf8Line, " \r\n\t" );
-
- // Parse the ALIAS list.
- while( tokens.HasMoreTokens() )
- {
- newAlias = tokens.GetNextToken();
- checkForDuplicates( newAlias );
- aPart->AddAlias( newAlias );
- }
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_RET( *line == 'F', "Invalid field line" );
-
- int id;
-
- if( sscanf( line + 1, "%d", &id ) != 1 || id < 0 )
- SCH_PARSE_ERROR( "invalid field ID", aReader, line + 1 );
-
- LIB_FIELD* field;
-
- if( (unsigned) id < MANDATORY_FIELDS )
- {
- field = aPart->GetField( id );
-
- // this will fire only if somebody broke a constructor or editor.
- // MANDATORY_FIELDS are always present in ram resident components, no
- // exceptions, and they always have their names set, even fixed fields.
- wxASSERT( field );
- }
- else
- {
- field = new LIB_FIELD( aPart.get(), id );
- aPart->AddDrawItem( field );
- }
-
- // Skip to the first double quote.
- while( *line != '"' && *line != 0 )
- line++;
-
- if( *line == 0 )
- SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, line );
-
- parseQuotedString( field->m_Text, aReader, line, &line, true );
-
- // Doctor the *.lib file field which has a "~" in blank fields. New saves will
- // not save like this.
- if( field->m_Text.size() == 1 && field->m_Text[0] == '~' )
- field->m_Text.clear();
-
- wxPoint pos;
-
- pos.x = parseInt( aReader, line, &line );
- pos.y = parseInt( aReader, line, &line );
- field->SetPosition( pos );
-
- wxSize textSize;
-
- textSize.x = textSize.y = parseInt( aReader, line, &line );
- field->SetTextSize( textSize );
-
- char textOrient = parseChar( aReader, line, &line );
-
- if( textOrient == 'H' )
- field->SetTextAngle( TEXT_ANGLE_HORIZ );
- else if( textOrient == 'V' )
- field->SetTextAngle( TEXT_ANGLE_VERT );
- else
- SCH_PARSE_ERROR( "invalid field text orientation parameter", aReader, line );
-
- char textVisible = parseChar( aReader, line, &line );
-
- if( textVisible == 'V' )
- field->SetVisible( true );
- else if ( textVisible == 'I' )
- field->SetVisible( false );
- else
- SCH_PARSE_ERROR( "invalid field text visibility parameter", aReader, line );
-
- // It may be technically correct to use the library version to determine if the field text
- // attributes are present. If anyone knows if that is valid and what version that would be,
- // please change this to test the library version rather than an EOL or the quoted string
- // of the field name.
- if( *line != 0 && *line != '"' )
- {
- char textHJustify = parseChar( aReader, line, &line );
-
- if( textHJustify == 'C' )
- field->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
- else if( textHJustify == 'L' )
- field->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
- else if( textHJustify == 'R' )
- field->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
- else
- SCH_PARSE_ERROR( "invalid field text horizontal justification", aReader, line );
-
- wxString attributes;
-
- parseUnquotedString( attributes, aReader, line, &line );
-
- size_t attrSize = attributes.size();
-
- if( !(attrSize == 3 || attrSize == 1 ) )
- SCH_PARSE_ERROR( "invalid field text attributes size", aReader, line );
-
- switch( (wxChar) attributes[0] )
- {
- case 'C': field->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
- case 'B': field->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
- case 'T': field->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
- default: SCH_PARSE_ERROR( "invalid field text vertical justification", aReader, line );
- }
-
- if( attrSize == 3 )
- {
- wxChar attr_1 = attributes[1];
- wxChar attr_2 = attributes[2];
-
- if( attr_1 == 'I' ) // Italic
- field->SetItalic( true );
- else if( attr_1 != 'N' ) // No italics is default, check for error.
- SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
-
- if ( attr_2 == 'B' ) // Bold
- field->SetBold( true );
- else if( attr_2 != 'N' ) // No bold is default, check for error.
- SCH_PARSE_ERROR( "invalid field text bold parameter", aReader, line );
- }
- }
-
- // Fields in RAM must always have names.
- if( (unsigned) id < MANDATORY_FIELDS )
- {
- // Fields in RAM must always have names, because we are trying to get
- // less dependent on field ids and more dependent on names.
- // Plus assumptions are made in the field editors.
- field->m_name = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
-
- // Ensure the VALUE field = the part name (can be not the case
- // with malformed libraries: edited by hand, or converted from other tools)
- if( id == VALUE )
- field->m_Text = aPart->GetName();
- }
- else
- {
- parseQuotedString( field->m_name, aReader, line, &line, true ); // Optional.
- }
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_RET( strCompare( "DRAW", line, &line ), "Invalid DRAW section" );
-
- line = aReader.ReadLine();
-
- while( line )
- {
- if( strCompare( "ENDDRAW", line, &line ) )
- return;
-
- switch( line[0] )
- {
- case 'A': // Arc
- aPart->AddDrawItem( loadArc( aPart, aReader ) );
- break;
-
- case 'C': // Circle
- aPart->AddDrawItem( loadCircle( aPart, aReader ) );
- break;
-
- case 'T': // Text
- aPart->AddDrawItem( loadText( aPart, aReader ) );
- break;
-
- case 'S': // Square
- aPart->AddDrawItem( loadRectangle( aPart, aReader ) );
- break;
-
- case 'X': // Pin Description
- aPart->AddDrawItem( loadPin( aPart, aReader ) );
- break;
-
- case 'P': // Polyline
- aPart->AddDrawItem( loadPolyLine( aPart, aReader ) );
- break;
-
- case 'B': // Bezier Curves
- aPart->AddDrawItem( loadBezier( aPart, aReader ) );
- break;
-
- case '#': // Comment
- case '\n': // Empty line
- case '\r':
- case 0:
- break;
-
- default:
- SCH_PARSE_ERROR( "undefined DRAW entry", aReader, line );
- }
-
- line = aReader.ReadLine();
- }
-
- SCH_PARSE_ERROR( "file ended prematurely loading component draw element", aReader, line );
-}
-
-
-FILL_T SCH_LEGACY_PLUGIN_CACHE::parseFillMode( FILE_LINE_READER& aReader, const char* aLine,
- const char** aOutput )
-{
- switch( parseChar( aReader, aLine, aOutput ) )
- {
- case 'F': return FILLED_SHAPE;
- case 'f': return FILLED_WITH_BG_BODYCOLOR;
- case 'N': return NO_FILL;
- default: SCH_PARSE_ERROR( "invalid fill type, expected f, F, or N", aReader, aLine );
- }
-}
-
-
-LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "A", line, &line ), NULL, "Invalid LIB_ARC definition" );
-
- LIB_ARC* arc = new LIB_ARC( aPart.get() );
-
- wxPoint center;
-
- center.x = parseInt( aReader, line, &line );
- center.y = parseInt( aReader, line, &line );
-
- arc->SetPosition( center );
- arc->SetRadius( parseInt( aReader, line, &line ) );
-
- int angle1 = parseInt( aReader, line, &line );
- int angle2 = parseInt( aReader, line, &line );
-
- NORMALIZE_ANGLE_POS( angle1 );
- NORMALIZE_ANGLE_POS( angle2 );
- arc->SetFirstRadiusAngle( angle1 );
- arc->SetSecondRadiusAngle( angle2 );
-
- arc->SetUnit( parseInt( aReader, line, &line ) );
- arc->SetConvert( parseInt( aReader, line, &line ) );
- arc->SetWidth( parseInt( aReader, line, &line ) );
-
- // Old libraries (version <= 2.2) do not have always this FILL MODE param
- // when fill mode is no fill (default mode).
- if( *line != 0 )
- arc->SetFillMode( parseFillMode( aReader, line, &line ) );
-
- // Actual Coordinates of arc ends are read from file
- if( *line != 0 )
- {
- wxPoint arcStart, arcEnd;
-
- arcStart.x = parseInt( aReader, line, &line );
- arcStart.y = parseInt( aReader, line, &line );
- arcEnd.x = parseInt( aReader, line, &line );
- arcEnd.y = parseInt( aReader, line, &line );
-
- arc->SetStart( arcStart );
- arc->SetEnd( arcEnd );
- }
- else
- {
- // Actual Coordinates of arc ends are not read from file
- // (old library), calculate them
- wxPoint arcStart( arc->GetRadius(), 0 );
- wxPoint arcEnd( arc->GetRadius(), 0 );
-
- RotatePoint( &arcStart.x, &arcStart.y, -angle1 );
- arcStart += arc->GetPosition();
- arc->SetStart( arcStart );
- RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 );
- arcEnd += arc->GetPosition();
- arc->SetEnd( arcEnd );
- }
-
- return arc;
-}
-
-
-LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "C", line, &line ), NULL, "Invalid LIB_CIRCLE definition" );
-
- LIB_CIRCLE* circle = new LIB_CIRCLE( aPart.get() );
-
- wxPoint center;
-
- center.x = parseInt( aReader, line, &line );
- center.y = parseInt( aReader, line, &line );
-
- circle->SetPosition( center );
- circle->SetRadius( parseInt( aReader, line, &line ) );
- circle->SetUnit( parseInt( aReader, line, &line ) );
- circle->SetConvert( parseInt( aReader, line, &line ) );
- circle->SetWidth( parseInt( aReader, line, &line ) );
-
- if( *line != 0 )
- circle->SetFillMode( parseFillMode( aReader, line, &line ) );
-
- return circle;
-}
-
-
-LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
+void SCH_LEGACY_PLUGIN_CACHE::Save( bool aSaveDocFile )
{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "T", line, &line ), NULL, "Invalid LIB_TEXT definition" );
-
- LIB_TEXT* text = new LIB_TEXT( aPart.get() );
-
- text->SetTextAngle( (double) parseInt( aReader, line, &line ) );
-
- wxPoint center;
-
- center.x = parseInt( aReader, line, &line );
- center.y = parseInt( aReader, line, &line );
- text->SetPosition( center );
-
- wxSize size;
+ if( !m_isModified )
+ return;
- size.x = size.y = parseInt( aReader, line, &line );
- text->SetTextSize( size );
- text->SetVisible( !parseInt( aReader, line, &line ) );
- text->SetUnit( parseInt( aReader, line, &line ) );
- text->SetConvert( parseInt( aReader, line, &line ) );
+ // Write through symlinks, don't replace them
+ wxFileName fn = GetRealFile();
- wxString str;
+ std::unique_ptr<FILE_OUTPUTFORMATTER> formatter( new FILE_OUTPUTFORMATTER( fn.GetFullPath() ) );
+ formatter->Print( 0, "%s %d.%d\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
+ formatter->Print( 0, "#encoding utf-8\n" );
- // If quoted string loading fails, load as not quoted string.
- if( *line == '"' )
- parseQuotedString( str, aReader, line, &line );
- else
+ for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
{
- parseUnquotedString( str, aReader, line, &line );
-
- // In old libs, "spaces" are replaced by '~' in unquoted strings:
- str.Replace( "~", " " );
- }
+ if( !it->second->IsRoot() )
+ continue;
- if( !str.IsEmpty() )
- {
- // convert two apostrophes back to double quote
- str.Replace( "''", "\"" );
+ saveSymbol( it->second->GetPart(), formatter );
}
- text->SetText( str );
-
- // Here things are murky and not well defined. At some point it appears the format
- // was changed to add text properties. However rather than add the token to the end of
- // the text definition, it was added after the string and no mention if the file
- // verion was bumped or not so this code make break on very old component libraries.
- //
- // Update: apparently even in the latest version this can be different so added a test
- // for end of line before checking for the text properties.
- if( LIB_VERSION( m_versionMajor, m_versionMinor ) > LIB_VERSION( 2, 0 ) && !is_eol( *line ) )
- {
- if( strCompare( "Italic", line, &line ) )
- text->SetItalic( true );
- else if( !strCompare( "Normal", line, &line ) )
- SCH_PARSE_ERROR( "invalid text stype, expected 'Normal' or 'Italic'", aReader, line );
-
- if( parseInt( aReader, line, &line ) > 0 )
- text->SetBold( true );
-
- // Some old libaries version > 2.0 do not have these options for text justification:
- if( !is_eol( *line ) )
- {
- switch( parseChar( aReader, line, &line ) )
- {
- case 'L': text->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); break;
- case 'C': text->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER ); break;
- case 'R': text->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); break;
- default: SCH_PARSE_ERROR( "invalid horizontal text justication; expected L, C, or R",
- aReader, line );
- }
+ formatter->Print( 0, "#\n#End Library\n" );
+ formatter.reset();
- switch( parseChar( aReader, line, &line ) )
- {
- case 'T': text->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); break;
- case 'C': text->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); break;
- case 'B': text->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); break;
- default: SCH_PARSE_ERROR( "invalid vertical text justication; expected T, C, or B",
- aReader, line );
- }
- }
- }
+ m_fileModTime = fn.GetModificationTime();
+ m_isModified = false;
- return text;
+ if( aSaveDocFile )
+ saveDocFile();
}
-LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "S", line, &line ), NULL, "Invalid LIB_RECTANGLE definition" );
-
- LIB_RECTANGLE* rectangle = new LIB_RECTANGLE( aPart.get() );
-
- wxPoint pos;
-
- pos.x = parseInt( aReader, line, &line );
- pos.y = parseInt( aReader, line, &line );
- rectangle->SetPosition( pos );
-
- wxPoint end;
-
- end.x = parseInt( aReader, line, &line );
- end.y = parseInt( aReader, line, &line );
- rectangle->SetEnd( end );
-
- rectangle->SetUnit( parseInt( aReader, line, &line ) );
- rectangle->SetConvert( parseInt( aReader, line, &line ) );
- rectangle->SetWidth( parseInt( aReader, line, &line ) );
-
- if( *line != 0 )
- rectangle->SetFillMode( parseFillMode( aReader, line, &line ) );
-
- return rectangle;
-}
-
-
-LIB_PIN* SCH_LEGACY_PLUGIN_CACHE::loadPin( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "X", line, &line ), NULL, "Invalid LIB_PIN definition" );
-
- LIB_PIN* pin = new LIB_PIN( aPart.get() );
-
- size_t pos = 2; // "X" plus ' ' space character.
- wxString tmp;
- wxString utf8Line = wxString::FromUTF8( line );
- wxStringTokenizer tokens( utf8Line, " \r\n\t" );
-
- if( tokens.CountTokens() < 11 )
- SCH_PARSE_ERROR( "invalid pin definition", aReader, line );
-
- pin->m_name = tokens.GetNextToken();
- pos += pin->m_name.size() + 1;
- pin->m_number = tokens.GetNextToken();
- pos += pin->m_number.size() + 1;
-
- long num;
- wxPoint position;
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin X coordinate", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- position.x = (int) num;
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin Y coordinate", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- position.y = (int) num;
- pin->m_position = position;
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin length", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- pin->m_length = (int) num;
-
-
- tmp = tokens.GetNextToken();
-
- if( tmp.size() > 1 )
- THROW_PARSE_ERROR( "invalid pin orientation", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- pin->m_orientation = tmp[0];
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin number text size", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- pin->m_numTextSize = (int) num;
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin name text size", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- pin->m_nameTextSize = (int) num;
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin unit", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- pin->m_Unit = (int) num;
-
- tmp = tokens.GetNextToken();
-
- if( !tmp.ToLong( &num ) )
- THROW_PARSE_ERROR( "invalid pin alternate body type", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- pin->m_Convert = (int) num;
-
- tmp = tokens.GetNextToken();
-
- if( tmp.size() != 1 )
- THROW_PARSE_ERROR( "invalid pin type", aReader.GetSource(), aReader.Line(),
- aReader.LineNumber(), pos );
-
- pos += tmp.size() + 1;
- char type = tmp[0];
-
- wxString attributes;
-
- switch( type )
- {
- case 'I': pin->m_type = PIN_INPUT; break;
- case 'O': pin->m_type = PIN_OUTPUT; break;
- case 'B': pin->m_type = PIN_BIDI; break;
- case 'T': pin->m_type = PIN_TRISTATE; break;
- case 'P': pin->m_type = PIN_PASSIVE; break;
- case 'U': pin->m_type = PIN_UNSPECIFIED; break;
- case 'W': pin->m_type = PIN_POWER_IN; break;
- case 'w': pin->m_type = PIN_POWER_OUT; break;
- case 'C': pin->m_type = PIN_OPENCOLLECTOR; break;
- case 'E': pin->m_type = PIN_OPENEMITTER; break;
- case 'N': pin->m_type = PIN_NC; break;
- default: THROW_PARSE_ERROR( "unknown pin type", aReader.GetSource(),
- aReader.Line(), aReader.LineNumber(), pos );
- }
-
- // Optional
- if( tokens.HasMoreTokens() ) /* Special Symbol defined */
- {
- tmp = tokens.GetNextToken();
-
- enum
- {
- INVERTED = 1 << 0,
- CLOCK = 1 << 1,
- LOWLEVEL_IN = 1 << 2,
- LOWLEVEL_OUT = 1 << 3,
- FALLING_EDGE = 1 << 4,
- NONLOGIC = 1 << 5
- };
-
- int flags = 0;
-
- for( int j = tmp.size(); j > 0; )
- {
- switch( tmp[--j].GetValue() )
- {
- case '~': break;
- case 'N': pin->m_attributes |= PIN_INVISIBLE; break;
- case 'I': flags |= INVERTED; break;
- case 'C': flags |= CLOCK; break;
- case 'L': flags |= LOWLEVEL_IN; break;
- case 'V': flags |= LOWLEVEL_OUT; break;
- case 'F': flags |= FALLING_EDGE; break;
- case 'X': flags |= NONLOGIC; break;
- default: THROW_PARSE_ERROR( "invalid pin attribut", aReader.GetSource(),
- aReader.Line(), aReader.LineNumber(), pos );
- }
-
- pos += 1;
- }
-
- switch( flags )
- {
- case 0: pin->m_shape = PINSHAPE_LINE; break;
- case INVERTED: pin->m_shape = PINSHAPE_INVERTED; break;
- case CLOCK: pin->m_shape = PINSHAPE_CLOCK; break;
- case INVERTED | CLOCK: pin->m_shape = PINSHAPE_INVERTED_CLOCK; break;
- case LOWLEVEL_IN: pin->m_shape = PINSHAPE_INPUT_LOW; break;
- case LOWLEVEL_IN | CLOCK: pin->m_shape = PINSHAPE_CLOCK_LOW; break;
- case LOWLEVEL_OUT: pin->m_shape = PINSHAPE_OUTPUT_LOW; break;
- case FALLING_EDGE: pin->m_shape = PINSHAPE_FALLING_EDGE_CLOCK; break;
- case NONLOGIC: pin->m_shape = PINSHAPE_NONLOGIC; break;
- default: SCH_PARSE_ERROR( "pin attributes do not define a valid pin shape", aReader, line );
- }
- }
-
- return pin;
-}
-
-
-LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "P", line, &line ), NULL, "Invalid LIB_POLYLINE definition" );
-
- LIB_POLYLINE* polyLine = new LIB_POLYLINE( aPart.get() );
-
- int points = parseInt( aReader, line, &line );
- polyLine->SetUnit( parseInt( aReader, line, &line ) );
- polyLine->SetConvert( parseInt( aReader, line, &line ) );
- polyLine->SetWidth( parseInt( aReader, line, &line ) );
- polyLine->Reserve( points );
-
- wxPoint pt;
-
- for( int i = 0; i < points; i++ )
- {
- pt.x = parseInt( aReader, line, &line );
- pt.y = parseInt( aReader, line, &line );
- polyLine->AddPoint( pt );
- }
-
- if( *line != 0 )
- polyLine->SetFillMode( parseFillMode( aReader, line, &line ) );
-
- return polyLine;
-}
-
-
-LIB_BEZIER* SCH_LEGACY_PLUGIN_CACHE::loadBezier( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_MSG( strCompare( "B", line, &line ), NULL, "Invalid LIB_BEZIER definition" );
-
- LIB_BEZIER* bezier = new LIB_BEZIER( aPart.get() );
-
- int points = parseInt( aReader, line, &line );
- bezier->SetUnit( parseInt( aReader, line, &line ) );
- bezier->SetConvert( parseInt( aReader, line, &line ) );
- bezier->SetWidth( parseInt( aReader, line, &line ) );
-
- wxPoint pt;
- bezier->Reserve( points );
-
- for( int i = 0; i < points; i++ )
- {
- pt.x = parseInt( aReader, line, &line );
- pt.y = parseInt( aReader, line, &line );
- bezier->AddPoint( pt );
- }
-
- if( *line != 0 )
- bezier->SetFillMode( parseFillMode( aReader, line, &line ) );
-
- return bezier;
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
- FILE_LINE_READER& aReader )
-{
- const char* line = aReader.Line();
-
- wxCHECK_RET( strCompare( "$FPLIST", line, &line ), "Invalid footprint filter list" );
-
- line = aReader.ReadLine();
-
- while( line )
- {
- if( strCompare( "$ENDFPLIST", line, &line ) )
- return;
-
- wxString footprint;
-
- parseUnquotedString( footprint, aReader, line, &line );
- aPart->GetFootprints().Add( footprint );
- line = aReader.ReadLine();
- }
-
- SCH_PARSE_ERROR( "file ended prematurely while loading footprint filters", aReader, line );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::Save( bool aSaveDocFile )
-{
- if( !m_isModified )
- return;
-
- // Write through symlinks, don't replace them
- wxFileName fn = GetRealFile();
-
- std::unique_ptr< FILE_OUTPUTFORMATTER > formatter( new FILE_OUTPUTFORMATTER( fn.GetFullPath() ) );
- formatter->Print( 0, "%s %d.%d\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
- formatter->Print( 0, "#encoding utf-8\n");
-
- for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
- {
- if( !it->second->IsRoot() )
- continue;
-
- saveSymbol( it->second->GetPart(), formatter );
- }
-
- formatter->Print( 0, "#\n#End Library\n" );
- formatter.reset();
-
- m_fileModTime = fn.GetModificationTime();
- m_isModified = false;
-
- if( aSaveDocFile )
- saveDocFile();
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveSymbol( LIB_PART* aSymbol,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
+void SCH_LEGACY_PLUGIN_CACHE::saveSymbol(
+ LIB_PART* aSymbol, std::unique_ptr<FILE_OUTPUTFORMATTER>& aFormatter )
{
wxCHECK_RET( aSymbol, "Invalid LIB_PART pointer." );
- LIB_FIELD& value = aSymbol->GetValueField();
-
- // First line: it s a comment (component name for readers)
- aFormatter->Print( 0, "#\n# %s\n#\n", TO_UTF8( value.GetText() ) );
-
- // Save data
- aFormatter->Print( 0, "DEF" );
-
- if( value.IsVisible() )
- {
- aFormatter->Print( 0, " %s", TO_UTF8( value.GetText() ) );
- }
- else
- {
- aFormatter->Print( 0, " ~%s", TO_UTF8( value.GetText() ) );
- }
-
- LIB_FIELD& reference = aSymbol->GetReferenceField();
-
- if( !reference.GetText().IsEmpty() )
- {
- aFormatter->Print( 0, " %s", TO_UTF8( reference.GetText() ) );
- }
- else
- {
- aFormatter->Print( 0, " ~" );
- }
-
- aFormatter->Print( 0, " %d %d %c %c %d %c %c\n",
- 0, aSymbol->GetPinNameOffset(),
- aSymbol->ShowPinNumbers() ? 'Y' : 'N',
- aSymbol->ShowPinNames() ? 'Y' : 'N',
- aSymbol->GetUnitCount(), aSymbol->UnitsLocked() ? 'L' : 'F',
- aSymbol->IsPower() ? 'P' : 'N' );
-
- timestamp_t dateModified = aSymbol->GetDateLastEdition();
-
- if( dateModified != 0 )
- {
- int sec = dateModified & 63;
- int min = ( dateModified >> 6 ) & 63;
- int hour = ( dateModified >> 12 ) & 31;
- int day = ( dateModified >> 17 ) & 31;
- int mon = ( dateModified >> 22 ) & 15;
- int year = ( dateModified >> 26 ) + 1990;
-
- aFormatter->Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec );
- }
-
- LIB_FIELDS fields;
- aSymbol->GetFields( fields );
-
- // Mandatory fields:
- // may have their own save policy so there is a separate loop for them.
- // Empty fields are saved, because the user may have set visibility,
- // size and orientation
- for( int i = 0; i < MANDATORY_FIELDS; ++i )
- {
- saveField( &fields[i], aFormatter );
- }
-
- // User defined fields:
- // may have their own save policy so there is a separate loop for them.
-
- int fieldId = MANDATORY_FIELDS; // really wish this would go away.
-
- for( unsigned i = MANDATORY_FIELDS; i < fields.size(); ++i )
- {
- // There is no need to save empty fields, i.e. no reason to preserve field
- // names now that fields names come in dynamically through the template
- // fieldnames.
- if( !fields[i].GetText().IsEmpty() )
- {
- fields[i].SetId( fieldId++ );
- saveField( &fields[i], aFormatter );
- }
- }
-
- // Save the alias list: a line starting by "ALIAS". The first alias is the root
- // and has the same name as the component. In the old library file format this
- // alias does not get added to the alias list.
- if( aSymbol->GetAliasCount() > 1 )
- {
- wxArrayString aliases = aSymbol->GetAliasNames();
-
- aFormatter->Print( 0, "ALIAS" );
-
- for( unsigned i = 1; i < aliases.size(); i++ )
- {
- aFormatter->Print( 0, " %s", TO_UTF8( aliases[i] ) );
- }
-
- aFormatter->Print( 0, "\n" );
- }
-
- wxArrayString footprints = aSymbol->GetFootprints();
-
- // Write the footprint filter list
- if( footprints.GetCount() != 0 )
- {
- aFormatter->Print( 0, "$FPLIST\n" );
-
- for( unsigned i = 0; i < footprints.GetCount(); i++ )
- {
- aFormatter->Print( 0, " %s\n", TO_UTF8( footprints[i] ) );
- }
-
- aFormatter->Print( 0, "$ENDFPLIST\n" );
- }
-
- // Save graphics items (including pins)
- if( !aSymbol->GetDrawItems().empty() )
- {
- // Sort the draw items in order to editing a file editing by hand.
- aSymbol->GetDrawItems().sort();
-
- aFormatter->Print( 0, "DRAW\n" );
-
- for( LIB_ITEM& item : aSymbol->GetDrawItems() )
- {
- switch( item.Type() )
- {
- case LIB_FIELD_T: // Fields have already been saved above.
- continue;
-
- case LIB_ARC_T:
- saveArc( (LIB_ARC*) &item, aFormatter );
- break;
-
- case LIB_BEZIER_T:
- saveBezier( (LIB_BEZIER*) &item, aFormatter );
- break;
-
- case LIB_CIRCLE_T:
- saveCircle( ( LIB_CIRCLE* ) &item, aFormatter );
- break;
-
- case LIB_PIN_T:
- savePin( (LIB_PIN* ) &item, aFormatter );
- break;
-
- case LIB_POLYLINE_T:
- savePolyLine( ( LIB_POLYLINE* ) &item, aFormatter );
- break;
-
- case LIB_RECTANGLE_T:
- saveRectangle( ( LIB_RECTANGLE* ) &item, aFormatter );
- break;
-
- case LIB_TEXT_T:
- saveText( ( LIB_TEXT* ) &item, aFormatter );
- break;
-
- default:
- ;
- }
- }
-
- aFormatter->Print( 0, "ENDDRAW\n" );
- }
-
- aFormatter->Print( 0, "ENDDEF\n" );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveArc( LIB_ARC* aArc,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." );
-
- int x1 = aArc->GetFirstRadiusAngle();
-
- if( x1 > 1800 )
- x1 -= 3600;
-
- int x2 = aArc->GetSecondRadiusAngle();
-
- if( x2 > 1800 )
- x2 -= 3600;
-
- aFormatter->Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n",
- aArc->GetPosition().x, aArc->GetPosition().y,
- aArc->GetRadius(), x1, x2, aArc->GetUnit(), aArc->GetConvert(),
- aArc->GetWidth(), fill_tab[aArc->GetFillMode()],
- aArc->GetStart().x, aArc->GetStart().y,
- aArc->GetEnd().x, aArc->GetEnd().y );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveBezier( LIB_BEZIER* aBezier,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aBezier && aBezier->Type() == LIB_BEZIER_T, "Invalid LIB_BEZIER object." );
-
- aFormatter->Print( 0, "B %u %d %d %d", (unsigned)aBezier->GetPoints().size(),
- aBezier->GetUnit(), aBezier->GetConvert(), aBezier->GetWidth() );
-
- for( const auto& pt : aBezier->GetPoints() )
- aFormatter->Print( 0, " %d %d", pt.x, pt.y );
-
- aFormatter->Print( 0, " %c\n", fill_tab[aBezier->GetFillMode()] );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveCircle( LIB_CIRCLE* aCircle,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aCircle && aCircle->Type() == LIB_CIRCLE_T, "Invalid LIB_CIRCLE object." );
-
- aFormatter->Print( 0, "C %d %d %d %d %d %d %c\n",
- aCircle->GetPosition().x, aCircle->GetPosition().y,
- aCircle->GetRadius(), aCircle->GetUnit(), aCircle->GetConvert(),
- aCircle->GetWidth(), fill_tab[aCircle->GetFillMode()] );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveField( LIB_FIELD* aField,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aField && aField->Type() == LIB_FIELD_T, "Invalid LIB_FIELD object." );
-
- int hjustify, vjustify;
- int id = aField->GetId();
- wxString text = aField->m_Text;
-
- hjustify = 'C';
-
- if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
- hjustify = 'L';
- else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
- hjustify = 'R';
-
- vjustify = 'C';
-
- if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
- vjustify = 'B';
- else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
- vjustify = 'T';
-
- aFormatter->Print( 0, "F%d %s %d %d %d %c %c %c %c%c%c",
- id,
- EscapedUTF8( text ).c_str(), // wraps in quotes
- aField->GetTextPos().x, aField->GetTextPos().y, aField->GetTextWidth(),
- aField->GetTextAngle() == 0 ? 'H' : 'V',
- aField->IsVisible() ? 'V' : 'I',
- hjustify, vjustify,
- aField->IsItalic() ? 'I' : 'N',
- aField->IsBold() ? 'B' : 'N' );
-
- /* Save field name, if necessary
- * Field name is saved only if it is not the default name.
- * Just because default name depends on the language and can change from
- * a country to another
- */
- wxString defName = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
-
- if( id >= FIELD1 && !aField->m_name.IsEmpty() && aField->m_name != defName )
- aFormatter->Print( 0, " %s", EscapedUTF8( aField->m_name ).c_str() );
-
- aFormatter->Print( 0, "\n" );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::savePin( LIB_PIN* aPin,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aPin && aPin->Type() == LIB_PIN_T, "Invalid LIB_PIN object." );
-
- int Etype;
-
- switch( aPin->GetType() )
- {
- default:
- case PIN_INPUT:
- Etype = 'I';
- break;
-
- case PIN_OUTPUT:
- Etype = 'O';
- break;
-
- case PIN_BIDI:
- Etype = 'B';
- break;
-
- case PIN_TRISTATE:
- Etype = 'T';
- break;
-
- case PIN_PASSIVE:
- Etype = 'P';
- break;
-
- case PIN_UNSPECIFIED:
- Etype = 'U';
- break;
-
- case PIN_POWER_IN:
- Etype = 'W';
- break;
-
- case PIN_POWER_OUT:
- Etype = 'w';
- break;
-
- case PIN_OPENCOLLECTOR:
- Etype = 'C';
- break;
-
- case PIN_OPENEMITTER:
- Etype = 'E';
- break;
-
- case PIN_NC:
- Etype = 'N';
- break;
- }
-
- if( !aPin->GetName().IsEmpty() )
- aFormatter->Print( 0, "X %s", TO_UTF8( aPin->GetName() ) );
- else
- aFormatter->Print( 0, "X ~" );
-
- aFormatter->Print( 0, " %s %d %d %d %c %d %d %d %d %c",
- aPin->GetNumber().IsEmpty() ? "~" : TO_UTF8( aPin->GetNumber() ),
- aPin->GetPosition().x, aPin->GetPosition().y,
- (int) aPin->GetLength(), (int) aPin->GetOrientation(),
- aPin->GetNumberTextSize(), aPin->GetNameTextSize(),
- aPin->GetUnit(), aPin->GetConvert(), Etype );
-
- if( aPin->GetShape() || !aPin->IsVisible() )
- aFormatter->Print( 0, " " );
-
- if( !aPin->IsVisible() )
- aFormatter->Print( 0, "N" );
-
- switch( aPin->GetShape() )
- {
- case PINSHAPE_LINE:
- break;
-
- case PINSHAPE_INVERTED:
- aFormatter->Print( 0, "I" );
- break;
-
- case PINSHAPE_CLOCK:
- aFormatter->Print( 0, "C" );
- break;
-
- case PINSHAPE_INVERTED_CLOCK:
- aFormatter->Print( 0, "IC" );
- break;
-
- case PINSHAPE_INPUT_LOW:
- aFormatter->Print( 0, "L" );
- break;
-
- case PINSHAPE_CLOCK_LOW:
- aFormatter->Print( 0, "CL" );
- break;
-
- case PINSHAPE_OUTPUT_LOW:
- aFormatter->Print( 0, "V" );
- break;
-
- case PINSHAPE_FALLING_EDGE_CLOCK:
- aFormatter->Print( 0, "F" );
- break;
-
- case PINSHAPE_NONLOGIC:
- aFormatter->Print( 0, "X" );
- break;
-
- default:
- assert( !"Invalid pin shape" );
- }
-
- aFormatter->Print( 0, "\n" );
-
- aPin->ClearFlags( IS_CHANGED );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::savePolyLine( LIB_POLYLINE* aPolyLine,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aPolyLine && aPolyLine->Type() == LIB_POLYLINE_T, "Invalid LIB_POLYLINE object." );
-
- int ccount = aPolyLine->GetCornerCount();
-
- aFormatter->Print( 0, "P %d %d %d %d", ccount, aPolyLine->GetUnit(), aPolyLine->GetConvert(),
- aPolyLine->GetWidth() );
-
- for( const auto& pt : aPolyLine->GetPolyPoints() )
- {
- aFormatter->Print( 0, " %d %d", pt.x, pt.y );
- }
-
- aFormatter->Print( 0, " %c\n", fill_tab[aPolyLine->GetFillMode()] );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveRectangle( LIB_RECTANGLE* aRectangle,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aRectangle && aRectangle->Type() == LIB_RECTANGLE_T,
- "Invalid LIB_RECTANGLE object." );
-
- aFormatter->Print( 0, "S %d %d %d %d %d %d %d %c\n",
- aRectangle->GetPosition().x, aRectangle->GetPosition().y,
- aRectangle->GetEnd().x, aRectangle->GetEnd().y,
- aRectangle->GetUnit(), aRectangle->GetConvert(),
- aRectangle->GetWidth(), fill_tab[aRectangle->GetFillMode()] );
-}
-
-
-void SCH_LEGACY_PLUGIN_CACHE::saveText( LIB_TEXT* aText,
- std::unique_ptr< FILE_OUTPUTFORMATTER >& aFormatter )
-{
- wxCHECK_RET( aText && aText->Type() == LIB_TEXT_T, "Invalid LIB_TEXT object." );
-
- wxString text = aText->GetText();
-
- if( text.Contains( wxT( " " ) ) || text.Contains( wxT( "~" ) ) || text.Contains( wxT( "\"" ) ) )
- {
- // convert double quote to similar-looking two apostrophes
- text.Replace( wxT( "\"" ), wxT( "''" ) );
- text = wxT( "\"" ) + text + wxT( "\"" );
- }
-
- aFormatter->Print( 0, "T %g %d %d %d %d %d %d %s", aText->GetTextAngle(),
- aText->GetTextPos().x, aText->GetTextPos().y,
- aText->GetTextWidth(), !aText->IsVisible(),
- aText->GetUnit(), aText->GetConvert(), TO_UTF8( text ) );
-
- aFormatter->Print( 0, " %s %d", aText->IsItalic() ? "Italic" : "Normal", aText->IsBold() );
-
- char hjustify = 'C';
-
- if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
- hjustify = 'L';
- else if( aText->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
- hjustify = 'R';
-
- char vjustify = 'C';
-
- if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
- vjustify = 'B';
- else if( aText->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
- vjustify = 'T';
-
- aFormatter->Print( 0, " %c %c\n", hjustify, vjustify );
+ LEGACY_PART_WRITER::WritePart( aSymbol, *aFormatter.get() );
}
diff --git a/eeschema/sch_legacy_plugin.h b/eeschema/sch_legacy_plugin.h
index 471d70333..b54b144fc 100644
--- a/eeschema/sch_legacy_plugin.h
+++ b/eeschema/sch_legacy_plugin.h
@@ -60,6 +60,10 @@ class LIB_ALIAS;
class SCH_LEGACY_PLUGIN : public SCH_PLUGIN
{
public:
+ static SCH_PLUGIN* create()
+ {
+ return new SCH_LEGACY_PLUGIN();
+ }
SCH_LEGACY_PLUGIN();
virtual ~SCH_LEGACY_PLUGIN();
--
2.20.1
Follow ups