kicad/eeschema/sch_sexpr_parser.cpp

2711 lines
72 KiB
C++
Raw Normal View History

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 CERN
*
* @author Wayne Stambaugh <stambaughw@gmail.com>
*
* 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 3 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/>.
*/
/**
* @file sch_sexpr_parser.cpp
* @brief Schematic and symbol library s-expression file format parser implementations.
*/
// For some reason wxWidgets is built with wxUSE_BASE64 unset so expose the wxWidgets
// base64 code.
#define wxUSE_BASE64 1
#include <wx/base64.h>
#include <wx/mstream.h>
#include <wx/tokenzr.h>
#include <common.h>
#include <lib_id.h>
#include <class_libentry.h>
#include <lib_arc.h>
#include <lib_bezier.h>
#include <lib_circle.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_edit_frame.h> // CMP_ORIENT_XXX
#include <sch_field.h>
#include <sch_line.h>
#include <sch_junction.h>
#include <sch_no_connect.h>
#include <sch_screen.h>
#include <sch_sexpr_parser.h>
#include <template_fieldnames.h>
using namespace TSCHEMATIC_T;
SCH_SEXPR_PARSER::SCH_SEXPR_PARSER( LINE_READER* aLineReader ) :
SCHEMATIC_LEXER( aLineReader ),
m_requiredVersion( 0 ),
2020-04-10 16:28:12 +00:00
m_fieldId( 0 ),
m_unit( 1 ),
m_convert( 1 )
{
}
bool SCH_SEXPR_PARSER::parseBool()
{
T token = NextTok();
if( token == T_yes )
return true;
else if( token == T_no )
return false;
else
Expecting( "yes or no" );
return false;
}
bool SCH_SEXPR_PARSER::IsTooRecent() const
{
return m_requiredVersion && m_requiredVersion > SEXPR_SYMBOL_LIB_FILE_VERSION;
}
void SCH_SEXPR_PARSER::ParseLib( LIB_PART_MAP& aSymbolLibMap )
{
T token;
NeedLEFT();
NextTok();
parseHeader( T_kicad_symbol_lib, SEXPR_SYMBOL_LIB_FILE_VERSION );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( token == T_symbol )
{
m_unit = 1;
m_convert = 1;
LIB_PART* symbol = ParseSymbol( aSymbolLibMap, m_requiredVersion );
aSymbolLibMap[symbol->GetName()] = symbol;
}
else
{
Expecting( "symbol" );
}
}
}
LIB_PART* SCH_SEXPR_PARSER::ParseSymbol( LIB_PART_MAP& aSymbolLibMap, int aFileVersion )
{
wxCHECK_MSG( CurTok() == T_symbol, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a symbol." ) );
T token;
long tmp;
wxString name;
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
wxString error;
LIB_ITEM* item;
std::unique_ptr<LIB_PART> symbol( new LIB_PART( wxEmptyString ) );
m_requiredVersion = aFileVersion;
symbol->SetUnitCount( 1 );
m_fieldId = MANDATORY_FIELDS;
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid symbol name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = FromUTF8();
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
LIB_ID id;
if( id.Parse( name, LIB_ID::ID_SCH ) >= 0 )
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
error.Printf( _( "Invalid library identifier in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
m_symbolName = id.GetLibItemName().wx_str();
symbol->SetName( m_symbolName );
symbol->SetLibId( id );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
case T_power:
symbol->SetPower();
NeedRIGHT();
break;
case T_pin_names:
parsePinNames( symbol );
break;
case T_pin_numbers:
token = NextTok();
if( token != T_hide )
Expecting( "hide" );
symbol->SetShowPinNumbers( false );
NeedRIGHT();
break;
case T_property:
parseProperty( symbol );
break;
case T_extends:
{
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf(
_( "Invalid symbol extends name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = FromUTF8();
auto it = aSymbolLibMap.find( name );
if( it == aSymbolLibMap.end() )
{
error.Printf(
_( "No parent for extended symbol %s in\nfile: \"%s\"\nline: %d\noffset: %d" ),
name.c_str(), CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
symbol->SetParent( it->second );
NeedRIGHT();
break;
}
case T_symbol:
{
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf(
_( "Invalid symbol unit name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = FromUTF8();
if( !name.StartsWith( m_symbolName ) )
{
error.Printf(
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
_( "Invalid symbol unit name prefix %s in\nfile: \"%s\"\n"
"line: %d\noffset: %d" ),
name.c_str(), CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = name.Right( name.Length() - m_symbolName.Length() - 1 );
wxStringTokenizer tokenizer( name, "_" );
if( tokenizer.CountTokens() != 2 )
{
error.Printf(
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
_( "Invalid symbol unit name suffix %s in\nfile: \"%s\"\n"
"line: %d\noffset: %d" ),
name.c_str(), CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
if( !tokenizer.GetNextToken().ToLong( &tmp ) )
{
error.Printf(
_( "Invalid symbol unit number %s in\nfile: \"%s\"\nline: %d\noffset: %d" ),
name.c_str(), CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
m_unit = static_cast<int>( tmp );
if( !tokenizer.GetNextToken().ToLong( &tmp ) )
{
error.Printf(
_( "Invalid symbol convert number %s in\nfile: \"%s\"\nline: %d\noffset: %d" ),
name.c_str(), CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
m_convert = static_cast<int>( tmp );
if( m_convert > 1 )
symbol->SetConversion( true, false );
if( m_unit > symbol->GetUnitCount() )
symbol->SetUnitCount( m_unit, false );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_arc:
case T_bezier:
case T_circle:
case T_pin:
case T_polyline:
case T_rectangle:
case T_text:
item = ParseDrawItem();
wxCHECK_MSG( item, nullptr, "Invalid draw item pointer." );
item->SetParent( symbol.get() );
symbol->AddDrawItem( item );
break;
default:
Expecting( "arc, bezier, circle, pin, polyline, rectangle, or text" );
};
}
m_unit = 1;
m_convert = 1;
break;
}
case T_arc:
case T_bezier:
case T_circle:
case T_pin:
case T_polyline:
case T_rectangle:
case T_text:
item = ParseDrawItem();
wxCHECK_MSG( item, nullptr, "Invalid draw item pointer." );
item->SetParent( symbol.get() );
symbol->AddDrawItem( item );
break;
default:
Expecting( "pin_names, pin_numbers, arc, bezier, circle, pin, polyline, "
"rectangle, or text" );
}
}
m_symbolName.clear();
return symbol.release();
}
LIB_ITEM* SCH_SEXPR_PARSER::ParseDrawItem()
{
switch( CurTok() )
{
case T_arc:
return static_cast<LIB_ITEM*>( parseArc() );
break;
case T_bezier:
return static_cast<LIB_ITEM*>( parseBezier() );
break;
case T_circle:
return static_cast<LIB_ITEM*>( parseCircle() );
break;
case T_pin:
return static_cast<LIB_ITEM*>( parsePin() );
break;
case T_polyline:
return static_cast<LIB_ITEM*>( parsePolyLine() );
break;
case T_rectangle:
return static_cast<LIB_ITEM*>( parseRectangle() );
break;
case T_text:
return static_cast<LIB_TEXT*>( parseText() );
break;
default:
Expecting( "arc, bezier, circle, pin, polyline, rectangle, or text" );
}
return nullptr;
}
double SCH_SEXPR_PARSER::parseDouble()
{
char* tmp;
errno = 0;
double fval = strtod( CurText(), &tmp );
if( errno )
{
wxString error;
error.Printf( _( "Invalid floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
if( CurText() == tmp )
{
wxString error;
error.Printf( _( "Missing floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
return fval;
}
void SCH_SEXPR_PARSER::parseStroke( STROKE_PARAMS& aStroke )
{
wxCHECK_RET( CurTok() == T_stroke,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a stroke." ) );
aStroke.SetWidth( Mils2iu( DEFAULT_LINE_THICKNESS ) );
aStroke.SetType( PLOT_DASH_TYPE::DEFAULT );
aStroke.SetColor( COLOR4D::UNSPECIFIED );
T token;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_width:
aStroke.SetWidth( parseInternalUnits( "stroke width" ) );
NeedRIGHT();
break;
case T_type:
{
token = NextTok();
switch( token )
{
case T_dash: aStroke.SetType( PLOT_DASH_TYPE::DASH ); break;
case T_dot: aStroke.SetType( PLOT_DASH_TYPE::DOT ); break;
case T_dash_dot: aStroke.SetType( PLOT_DASH_TYPE::DASHDOT ); break;
case T_solid: aStroke.SetType( PLOT_DASH_TYPE::SOLID ); break;
default:
Expecting( "solid, dash, dash_dot, or dot" );
}
NeedRIGHT();
break;
}
case T_color:
{
COLOR4D color;
color.r = parseInt( "red" ) / 255.0;
color.g = parseInt( "green" ) / 255.0;
color.b = parseInt( "blue" ) / 255.0;
color.a = Clamp( parseDouble( "alpha" ), 0.0, 1.0 );
aStroke.SetColor( color );
NeedRIGHT();
break;
}
default:
Expecting( "width, type, or color" );
}
}
}
void SCH_SEXPR_PARSER::parseFill( FILL_PARAMS& aFill )
{
wxCHECK_RET( CurTok() == T_fill,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as fill." ) );
aFill.m_FillType = NO_FILL;
aFill.m_Color = COLOR4D::UNSPECIFIED;
T token;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_type:
{
token = NextTok();
switch( token )
{
case T_none: aFill.m_FillType = NO_FILL; break;
case T_outline: aFill.m_FillType = FILLED_SHAPE; break;
case T_background: aFill.m_FillType = FILLED_WITH_BG_BODYCOLOR; break;
default:
Expecting( "none, outline, or background" );
}
NeedRIGHT();
break;
}
case T_color:
{
COLOR4D color;
color.r = parseInt( "red" ) / 255.0;
color.g = parseInt( "green" ) / 255.0;
color.b = parseInt( "blue" ) / 255.0;
color.a = Clamp( parseDouble( "alpha" ), 0.0, 1.0 );
aFill.m_Color = color;
NeedRIGHT();
break;
}
default:
Expecting( "type or color" );
}
}
}
void SCH_SEXPR_PARSER::parseEDA_TEXT( EDA_TEXT* aText )
{
wxCHECK_RET( aText && CurTok() == T_effects,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
T token;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_LEFT )
token = NextTok();
switch( token )
{
case T_font:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_LEFT )
token = NextTok();
switch( token )
{
case T_size:
{
wxSize sz;
sz.SetHeight( parseInternalUnits( "text height" ) );
sz.SetWidth( parseInternalUnits( "text width" ) );
aText->SetTextSize( sz );
NeedRIGHT();
break;
}
case T_thickness:
2020-04-14 12:25:00 +00:00
aText->SetTextThickness( parseInternalUnits( "text thickness" ) );
NeedRIGHT();
break;
case T_bold:
aText->SetBold( true );
break;
case T_italic:
aText->SetItalic( true );
break;
default:
Expecting( "size, bold, or italic" );
}
}
break;
case T_justify:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
switch( token )
{
case T_left:
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
break;
case T_right:
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
break;
case T_top:
aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
break;
case T_bottom:
aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
break;
case T_mirror:
aText->SetMirrored( true );
break;
default:
Expecting( "left, right, top, bottom, or mirror" );
}
}
break;
case T_hide:
aText->SetVisible( false );
break;
default:
Expecting( "font, justify, or hide" );
}
}
}
void SCH_SEXPR_PARSER::parseHeader( TSCHEMATIC_T::T aHeaderType, int aFileVersion )
{
wxCHECK_RET( CurTok() == aHeaderType,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
NeedLEFT();
T tok = NextTok();
if( tok == T_version )
{
m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
NeedRIGHT();
// Skip the host name and host build version information.
NeedLEFT();
NeedSYMBOL();
NeedSYMBOL();
NeedSYMBOL();
NeedRIGHT();
}
else
{
m_requiredVersion = aFileVersion;
// Skip the host name and host build version information.
NeedSYMBOL();
NeedSYMBOL();
NeedRIGHT();
}
}
void SCH_SEXPR_PARSER::parsePinNames( std::unique_ptr<LIB_PART>& aSymbol )
{
wxCHECK_RET( CurTok() == T_pin_names,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
wxT( " as a pin_name token." ) );
wxString error;
T token = NextTok();
if( token == T_LEFT )
{
token = NextTok();
if( token != T_offset )
Expecting( "offset" );
aSymbol->SetPinNameOffset( parseInternalUnits( "pin name offset" ) );
NeedRIGHT();
token = NextTok(); // Either ) or hide
}
if( token == T_hide )
{
aSymbol->SetShowPinNames( false );
NeedRIGHT();
}
else if( token != T_RIGHT )
{
error.Printf(
_( "Invalid symbol names definition in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
}
void SCH_SEXPR_PARSER::parseProperty( std::unique_ptr<LIB_PART>& aSymbol )
{
wxCHECK_RET( CurTok() == T_property,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
wxT( " as a property token." ) );
wxCHECK( aSymbol, /* void */ );
wxString error;
wxString name;
wxString value;
std::unique_ptr<LIB_FIELD> field( new LIB_FIELD( aSymbol.get(), MANDATORY_FIELDS ) );
T token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid property name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = FromUTF8();
if( name.IsEmpty() )
{
error.Printf( _( "Empty property name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
field->SetName( name );
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid property value in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
// Empty property values are valid.
value = FromUTF8();
field->SetText( value );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_id:
field->SetId( parseInt( "field ID" ) );
NeedRIGHT();
break;
case T_at:
field->SetPosition( parseXY() );
field->SetTextAngle( static_cast<int>( parseDouble( "text angle" ) * 10.0 ) );
NeedRIGHT();
break;
case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( field.get() ) );
break;
default:
Expecting( "id, at or effects" );
}
}
LIB_FIELD* existingField;
if( field->GetId() < MANDATORY_FIELDS )
{
existingField = aSymbol->GetField( field->GetId() );
*existingField = *field;
}
else if( name == "ki_keywords" )
{
// Not a LIB_FIELD object yet.
aSymbol->SetKeyWords( value );
}
else if( name == "ki_description" )
{
// Not a LIB_FIELD object yet.
aSymbol->SetDescription( value );
}
else if( name == "ki_fp_filters" )
{
// Not a LIB_FIELD object yet.
wxArrayString filters;
wxStringTokenizer tokenizer( value );
while( tokenizer.HasMoreTokens() )
filters.Add( tokenizer.GetNextToken() );
aSymbol->SetFootprintFilters( filters );
}
else if( name == "ki_locked" )
{
// This is a temporary LIB_FIELD object until interchangeable units are determined on
// the fly.
aSymbol->LockUnits( true );
}
else
{
existingField = aSymbol->GetField( field->GetId() );
if( !existingField )
{
aSymbol->AddDrawItem( field.release() );
}
else
{
*existingField = *field;
}
}
}
LIB_ARC* SCH_SEXPR_PARSER::parseArc()
{
wxCHECK_MSG( CurTok() == T_arc, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as an arc token." ) );
T token;
wxPoint startPoint;
wxPoint midPoint;
wxPoint endPoint;
wxPoint pos;
FILL_PARAMS fill;
bool hasMidPoint = false;
std::unique_ptr<LIB_ARC> arc( new LIB_ARC( nullptr ) );
arc->SetUnit( m_unit );
arc->SetConvert( m_convert );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_start:
startPoint = parseXY();
NeedRIGHT();
break;
case T_mid:
midPoint = parseXY();
NeedRIGHT();
hasMidPoint = true;
break;
case T_end:
endPoint = parseXY();
NeedRIGHT();
break;
case T_radius:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
pos = parseXY();
NeedRIGHT();
break;
case T_length:
arc->SetRadius( parseInternalUnits( "radius length" ) );
NeedRIGHT();
break;
case T_angles:
{
int angle1 = KiROUND( parseDouble( "start radius angle" ) * 10.0 );
int angle2 = KiROUND( parseDouble( "end radius angle" ) * 10.0 );
NORMALIZE_ANGLE_POS( angle1 );
NORMALIZE_ANGLE_POS( angle2 );
arc->SetFirstRadiusAngle( angle1 );
arc->SetSecondRadiusAngle( angle2 );
NeedRIGHT();
break;
}
default:
Expecting( "at, length, or angle" );
}
}
break;
case T_stroke:
NeedLEFT();
token = NextTok();
if( token != T_width )
Expecting( "width" );
arc->SetWidth( parseInternalUnits( "stroke width" ) );
NeedRIGHT(); // Closes width token;
NeedRIGHT(); // Closes stroke token;
break;
case T_fill:
parseFill( fill );
arc->SetFillMode( fill.m_FillType );
break;
default:
Expecting( "start, end, radius, stroke, or fill" );
}
}
arc->SetPosition( pos );
arc->SetStart( startPoint );
arc->SetEnd( endPoint );
if( hasMidPoint )
{
VECTOR2I center = GetArcCenter( arc->GetStart(), midPoint, arc->GetEnd() );
arc->SetPosition( wxPoint( center.x, center.y ) );
// @todo Calculate the radius.
arc->CalcRadiusAngles();
}
return arc.release();
}
LIB_BEZIER* SCH_SEXPR_PARSER::parseBezier()
{
wxCHECK_MSG( CurTok() == T_bezier, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a bezier." ) );
T token;
FILL_PARAMS fill;
std::unique_ptr<LIB_BEZIER> bezier( new LIB_BEZIER( nullptr ) );
bezier->SetUnit( m_unit );
bezier->SetConvert( m_convert );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_pts:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( token != T_xy )
Expecting( "xy" );
bezier->AddPoint( parseXY() );
NeedRIGHT();
}
break;
case T_stroke:
NeedLEFT();
token = NextTok();
if( token != T_width )
Expecting( "width" );
bezier->SetWidth( parseInternalUnits( "stroke width" ) );
NeedRIGHT(); // Closes width token;
NeedRIGHT(); // Closes stroke token;
break;
case T_fill:
parseFill( fill );
bezier->SetFillMode( fill.m_FillType );
break;
default:
Expecting( "pts, stroke, or fill" );
}
}
return bezier.release();
}
LIB_CIRCLE* SCH_SEXPR_PARSER::parseCircle()
{
wxCHECK_MSG( CurTok() == T_circle, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a circle token." ) );
T token;
FILL_PARAMS fill;
std::unique_ptr<LIB_CIRCLE> circle( new LIB_CIRCLE( nullptr ) );
circle->SetUnit( m_unit );
circle->SetConvert( m_convert );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_center:
circle->SetPosition( parseXY() );
NeedRIGHT();
break;
case T_radius:
circle->SetRadius( parseInternalUnits( "radius length" ) );
NeedRIGHT();
break;
case T_stroke:
NeedLEFT();
token = NextTok();
if( token != T_width )
Expecting( "width" );
circle->SetWidth( parseInternalUnits( "stroke width" ) );
NeedRIGHT(); // Closes width token;
NeedRIGHT(); // Closes stroke token;
break;
case T_fill:
parseFill( fill );
circle->SetFillMode( fill.m_FillType );
break;
default:
Expecting( "start, end, radius, stroke, or fill" );
}
}
return circle.release();
}
LIB_PIN* SCH_SEXPR_PARSER::parsePin()
{
auto parseType = [&]( T token ) -> ELECTRICAL_PINTYPE
{
switch( token )
{
case T_input: return ELECTRICAL_PINTYPE::PT_INPUT;
case T_output: return ELECTRICAL_PINTYPE::PT_OUTPUT;
case T_bidirectional: return ELECTRICAL_PINTYPE::PT_BIDI;
case T_tri_state: return ELECTRICAL_PINTYPE::PT_TRISTATE;
case T_passive: return ELECTRICAL_PINTYPE::PT_PASSIVE;
case T_unspecified: return ELECTRICAL_PINTYPE::PT_UNSPECIFIED;
case T_power_in: return ELECTRICAL_PINTYPE::PT_POWER_IN;
case T_power_out: return ELECTRICAL_PINTYPE::PT_POWER_OUT;
case T_open_collector: return ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR;
case T_open_emitter: return ELECTRICAL_PINTYPE::PT_OPENEMITTER;
case T_unconnected: return ELECTRICAL_PINTYPE::PT_NC;
default:
Expecting( "input, output, bidirectional, tri_state, passive, "
"unspecified, power_in, power_out, open_collector, "
"open_emitter, or unconnected" );
return ELECTRICAL_PINTYPE::PT_UNSPECIFIED;
}
};
auto parseShape = [&]( T token ) -> GRAPHIC_PINSHAPE
{
switch( token )
{
case T_line: return GRAPHIC_PINSHAPE::LINE;
case T_inverted: return GRAPHIC_PINSHAPE::INVERTED;
case T_clock: return GRAPHIC_PINSHAPE::CLOCK;
case T_inverted_clock: return GRAPHIC_PINSHAPE::INVERTED_CLOCK;
case T_input_low: return GRAPHIC_PINSHAPE::INPUT_LOW;
case T_clock_low: return GRAPHIC_PINSHAPE::CLOCK_LOW;
case T_output_low: return GRAPHIC_PINSHAPE::OUTPUT_LOW;
case T_edge_clock_high: return GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK;
case T_non_logic: return GRAPHIC_PINSHAPE::NONLOGIC;
default:
Expecting( "line, inverted, clock, inverted_clock, input_low, "
"clock_low, output_low, edge_clock_high, non_logic" );
return GRAPHIC_PINSHAPE::LINE;
}
};
wxCHECK_MSG( CurTok() == T_pin, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a pin token." ) );
T token;
wxString tmp;
wxString error;
std::unique_ptr<LIB_PIN> pin( new LIB_PIN( nullptr ) );
pin->SetUnit( m_unit );
pin->SetConvert( m_convert );
// Pin electrical type.
token = NextTok();
pin->SetType( parseType( token ) );
// Pin shape.
token = NextTok();
pin->SetShape( parseShape( token ) );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_hide )
{
pin->SetVisible( false );
continue;
}
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
pin->SetPosition( parseXY() );
switch( parseInt( "pin orientation" ) )
{
case 0:
pin->SetOrientation( PIN_RIGHT );
break;
case 90:
pin->SetOrientation( PIN_UP );
break;
case 180:
pin->SetOrientation( PIN_LEFT );
break;
case 270:
pin->SetOrientation( PIN_DOWN );
break;
default:
Expecting( "0, 90, 180, or 270" );
}
NeedRIGHT();
break;
case T_length:
pin->SetLength( parseInternalUnits( "pin length" ) );
NeedRIGHT();
break;
case T_name:
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid pin name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
pin->SetName( FromUTF8() );
token = NextTok();
if( token != T_RIGHT )
{
token = NextTok();
if( token == T_effects )
{
// The EDA_TEXT font effects formatting is used so use and EDA_TEXT object
// so duplicate parsing is not required.
EDA_TEXT text;
parseEDA_TEXT( &text );
pin->SetNameTextSize( text.GetTextHeight() );
NeedRIGHT();
}
else
{
Expecting( "effects" );
}
}
break;
case T_number:
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid pin number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
pin->SetNumber( FromUTF8() );
token = NextTok();
if( token != T_RIGHT )
{
token = NextTok();
if( token == T_effects )
{
// The EDA_TEXT font effects formatting is used so use and EDA_TEXT object
// so duplicate parsing is not required.
EDA_TEXT text;
parseEDA_TEXT( &text );
pin->SetNumberTextSize( text.GetTextHeight() );
NeedRIGHT();
}
else
{
Expecting( "effects" );
}
}
break;
case T_alternate:
{
LIB_PIN::ALT alt;
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid alternate pin name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
alt.m_Name = FromUTF8();
token = NextTok();
alt.m_Type = parseType( token );
token = NextTok();
alt.m_Shape = parseShape( token );
pin->GetAlternates()[ alt.m_Name ] = alt;
NeedRIGHT();
}
break;
default:
Expecting( "at, name, number, length, or alternate" );
}
}
return pin.release();
}
LIB_POLYLINE* SCH_SEXPR_PARSER::parsePolyLine()
{
wxCHECK_MSG( CurTok() == T_polyline, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a polyline." ) );
T token;
FILL_PARAMS fill;
std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( nullptr ) );
polyLine->SetUnit( m_unit );
polyLine->SetConvert( m_convert );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_pts:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( token != T_xy )
Expecting( "xy" );
polyLine->AddPoint( parseXY() );
NeedRIGHT();
}
break;
case T_stroke:
NeedLEFT();
token = NextTok();
if( token != T_width )
Expecting( "width" );
polyLine->SetWidth( parseInternalUnits( "stroke width" ) );
NeedRIGHT(); // Closes width token;
NeedRIGHT(); // Closes stroke token;
break;
case T_fill:
parseFill( fill );
polyLine->SetFillMode( fill.m_FillType );
break;
default:
Expecting( "pts, stroke, or fill" );
}
}
return polyLine.release();
}
LIB_RECTANGLE* SCH_SEXPR_PARSER::parseRectangle()
{
wxCHECK_MSG( CurTok() == T_rectangle, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a rectangle token." ) );
T token;
FILL_PARAMS fill;
std::unique_ptr<LIB_RECTANGLE> rectangle( new LIB_RECTANGLE( nullptr ) );
rectangle->SetUnit( m_unit );
rectangle->SetConvert( m_convert );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_start:
rectangle->SetPosition( parseXY() );
NeedRIGHT();
break;
case T_end:
rectangle->SetEnd( parseXY() );
NeedRIGHT();
break;
case T_stroke:
NeedLEFT();
token = NextTok();
if( token != T_width )
Expecting( "width" );
rectangle->SetWidth( parseInternalUnits( "stroke width" ) );
NeedRIGHT(); // Closes width token;
NeedRIGHT(); // Closes stroke token;
break;
case T_fill:
parseFill( fill );
rectangle->SetFillMode( fill.m_FillType );
break;
default:
Expecting( "start, end, stroke, or fill" );
}
}
return rectangle.release();
}
LIB_TEXT* SCH_SEXPR_PARSER::parseText()
{
wxCHECK_MSG( CurTok() == T_text, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a text token." ) );
T token;
wxString tmp;
wxString error;
std::unique_ptr<LIB_TEXT> text( new LIB_TEXT( nullptr ) );
text->SetUnit( m_unit );
text->SetConvert( m_convert );
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid text string in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
text->SetText( FromUTF8() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
text->SetPosition( parseXY() );
text->SetTextAngle( parseDouble( "text angle" ) );
NeedRIGHT();
break;
case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( text.get() ) );
break;
default:
Expecting( "at or effects" );
}
}
return text.release();
}
void SCH_SEXPR_PARSER::parsePAGE_INFO( PAGE_INFO& aPageInfo )
{
wxCHECK_RET( ( CurTok() == T_page && m_requiredVersion <= 20200506 ) || CurTok() == T_paper,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
T token;
NeedSYMBOL();
wxString pageType = FromUTF8();
if( !aPageInfo.SetType( pageType ) )
{
wxString err;
err.Printf( _( "Page type \"%s\" is not valid " ), GetChars( FromUTF8() ) );
THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
if( pageType == PAGE_INFO::Custom )
{
double width = parseDouble( "width" ); // width in mm
// Perform some controls to avoid crashes if the size is edited by hands
if( width < 100.0 )
width = 100.0;
else if( width > 1200.0 )
width = 1200.0;
double height = parseDouble( "height" ); // height in mm
if( height < 100.0 )
height = 100.0;
else if( height > 1200.0 )
height = 1200.0;
aPageInfo.SetWidthMils( Mm2mils( width ) );
aPageInfo.SetHeightMils( Mm2mils( height ) );
}
token = NextTok();
if( token == T_portrait )
{
aPageInfo.SetPortrait( true );
NeedRIGHT();
}
else if( token != T_RIGHT )
{
Expecting( "portrait" );
}
}
void SCH_SEXPR_PARSER::parseTITLE_BLOCK( TITLE_BLOCK& aTitleBlock )
{
wxCHECK_RET( CurTok() == T_title_block,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
wxT( " as TITLE_BLOCK." ) );
T token;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_title:
NextTok();
aTitleBlock.SetTitle( FromUTF8() );
break;
case T_date:
NextTok();
aTitleBlock.SetDate( FromUTF8() );
break;
case T_rev:
NextTok();
aTitleBlock.SetRevision( FromUTF8() );
break;
case T_company:
NextTok();
aTitleBlock.SetCompany( FromUTF8() );
break;
case T_comment:
{
int commentNumber = parseInt( "comment" );
switch( commentNumber )
{
case 1:
NextTok();
aTitleBlock.SetComment( 0, FromUTF8() );
break;
case 2:
NextTok();
aTitleBlock.SetComment( 1, FromUTF8() );
break;
case 3:
NextTok();
aTitleBlock.SetComment( 2, FromUTF8() );
break;
case 4:
NextTok();
aTitleBlock.SetComment( 3, FromUTF8() );
break;
case 5:
NextTok();
aTitleBlock.SetComment( 4, FromUTF8() );
break;
case 6:
NextTok();
aTitleBlock.SetComment( 5, FromUTF8() );
break;
case 7:
NextTok();
aTitleBlock.SetComment( 6, FromUTF8() );
break;
case 8:
NextTok();
aTitleBlock.SetComment( 7, FromUTF8() );
break;
case 9:
NextTok();
aTitleBlock.SetComment( 8, FromUTF8() );
break;
default:
wxString err;
err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
break;
}
default:
Expecting( "title, date, rev, company, or comment" );
}
NeedRIGHT();
}
}
SCH_FIELD* SCH_SEXPR_PARSER::parseSchField( SCH_ITEM* aParent )
{
wxCHECK_MSG( CurTok() == T_property, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
wxT( " as a property token." ) );
wxString error;
wxString name;
wxString value;
T token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid property name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = FromUTF8();
if( name.IsEmpty() )
{
error.Printf( _( "Empty property name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid property value in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
// Empty property values are valid.
value = FromUTF8();
std::unique_ptr<SCH_FIELD> field( new SCH_FIELD( wxDefaultPosition, -1, aParent, name ) );
field->SetText( value );
field->SetVisible( true );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_id:
field->SetId( parseInt( "field ID" ) );
NeedRIGHT();
break;
case T_at:
field->SetPosition( parseXY() );
field->SetTextAngle( static_cast<int>( parseDouble( "text angle" ) * 10.0 ) );
NeedRIGHT();
break;
case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( field.get() ) );
break;
default:
Expecting( "at or effects" );
}
}
return field.release();
}
SCH_SHEET_PIN* SCH_SEXPR_PARSER::parseSchSheetPin( SCH_SHEET* aSheet )
{
wxCHECK_MSG( aSheet != nullptr, nullptr, "" );
wxCHECK_MSG( CurTok() == T_pin, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
wxT( " as a sheet pin token." ) );
wxString error;
wxString name;
wxString shape;
T token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid sheet pin name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
name = FromUTF8();
if( name.IsEmpty() )
{
error.Printf( _( "Empty sheet pin name in\nfile: \"%s\"\nline: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
std::unique_ptr<SCH_SHEET_PIN> sheetPin( new SCH_SHEET_PIN( aSheet, wxPoint( 0, 0 ), name ) );
token = NextTok();
switch( token )
{
case T_input: sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_INPUT ); break;
case T_output: sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_OUTPUT ); break;
case T_bidirectional: sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_BIDI ); break;
case T_tri_state: sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_TRISTATE ); break;
case T_passive: sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_UNSPECIFIED ); break;
default:
Expecting( "input, output, bidirectional, tri_state, or passive" );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
{
sheetPin->SetPosition( parseXY() );
double angle = parseDouble( "sheet pin angle (side)" );
if( angle == 0.0 )
sheetPin->SetEdge( SHEET_RIGHT_SIDE );
else if( angle == 90.0 )
sheetPin->SetEdge( SHEET_TOP_SIDE );
else if( angle == 180.0 )
sheetPin->SetEdge( SHEET_LEFT_SIDE );
else if( angle == 270.0 )
sheetPin->SetEdge( SHEET_BOTTOM_SIDE );
else
Expecting( "0, 90, 180, or 270" );
NeedRIGHT();
break;
}
case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( sheetPin.get() ) );
break;
default:
Expecting( "at or effects" );
}
}
return sheetPin.release();
}
void SCH_SEXPR_PARSER::parseSchSymbolInstances( SCH_SCREEN* aScreen )
{
wxCHECK_RET( CurTok() == T_symbol_instances,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
wxT( " as a instances token." ) );
wxCHECK( aScreen, /* void */ );
T token;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_path:
{
NeedSYMBOL();
COMPONENT_INSTANCE_REFERENCE instance;
instance.m_Path = KIID_PATH( FromUTF8() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_reference:
NeedSYMBOL();
instance.m_Reference = FromUTF8();
NeedRIGHT();
break;
case T_unit:
instance.m_Unit = parseInt( "symbol unit" );
NeedRIGHT();
break;
default:
Expecting( "path or unit" );
}
}
aScreen->m_symbolInstances.emplace_back( instance );
break;
}
default:
Expecting( "path" );
}
}
}
void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopyableOnly, int aFileVersion )
{
wxCHECK( aSheet != nullptr, /* void */ );
SCH_SCREEN* screen = aSheet->GetScreen();
wxCHECK( screen != nullptr, /* void */ );
if( aIsCopyableOnly )
m_requiredVersion = aFileVersion;
T token;
if( !aIsCopyableOnly )
{
NeedLEFT();
NextTok();
if( CurTok() != T_kicad_sch )
Expecting( "kicad_sch" );
parseHeader( T_kicad_sch, SEXPR_SCHEMATIC_FILE_VERSION );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( aIsCopyableOnly && token == T_EOF )
break;
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( !aIsCopyableOnly && token == T_page && m_requiredVersion <= 20200506 )
token = T_paper;
switch( token )
{
case T_paper:
{
if( aIsCopyableOnly )
Unexpected( T_paper );
PAGE_INFO pageInfo;
parsePAGE_INFO( pageInfo );
screen->SetPageSettings( pageInfo );
break;
}
case T_page:
{
if( aIsCopyableOnly )
Unexpected( T_page );
// Only saved for top-level sniffing in Kicad Manager frame and other external
// tool usage with flat hierarchies
NeedSYMBOLorNUMBER();
NeedSYMBOLorNUMBER();
NeedRIGHT();
break;
}
case T_title_block:
{
if( aIsCopyableOnly )
Unexpected( T_title_block );
TITLE_BLOCK tb;
parseTITLE_BLOCK( tb );
screen->SetTitleBlock( tb );
break;
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
case T_lib_symbols:
{
// Dummy map. No derived symbols are allowed in the library cache.
LIB_PART_MAP symbolLibMap;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_symbol:
screen->AddLibSymbol( ParseSymbol( symbolLibMap ) );
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
break;
default:
Expecting( "symbol" );
}
}
break;
}
case T_symbol:
screen->Append( static_cast<SCH_ITEM*>( parseSchematicSymbol() ) );
break;
case T_image:
screen->Append( static_cast<SCH_ITEM*>( parseImage() ) );
break;
case T_sheet:
{
SCH_SHEET* sheet = parseSheet();
// Set the parent to aSheet. This effectively creates a method to find
// the root sheet from any sheet so a pointer to the root sheet does not
// need to be stored globally. Note: this is not the same as a hierarchy.
// Complex hierarchies can have multiple copies of a sheet. This only
// provides a simple tree to find the root sheet.
sheet->SetParent( aSheet );
screen->Append( static_cast<SCH_ITEM*>( sheet ) );
break;
}
case T_junction:
screen->Append( static_cast<SCH_ITEM*>( parseJunction() ) );
break;
case T_no_connect:
screen->Append( static_cast<SCH_ITEM*>( parseNoConnect() ) );
break;
case T_bus_entry:
screen->Append( static_cast<SCH_ITEM*>( parseBusEntry() ) );
break;
case T_polyline:
case T_bus:
case T_wire:
screen->Append( static_cast<SCH_ITEM*>( parseLine() ) );
break;
case T_text:
case T_label:
case T_global_label:
case T_hierarchical_label:
screen->Append( static_cast<SCH_ITEM*>( parseSchText() ) );
break;
case T_symbol_instances:
if( aIsCopyableOnly )
Unexpected( T_symbol_instances );
parseSchSymbolInstances( screen );
break;
case T_bus_alias:
if( aIsCopyableOnly )
Unexpected( T_bus_alias );
parseBusAlias( screen );
break;
default:
Expecting( "symbol, paper, page, title_block, bitmap, sheet, junction, no_connect, "
"bus_entry, line, bus, text, label, global_label, hierarchical_label, "
"symbol_instances, or bus_alias" );
}
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
screen->UpdateLocalLibSymbolLinks();
}
SCH_COMPONENT* SCH_SEXPR_PARSER::parseSchematicSymbol()
{
wxCHECK_MSG( CurTok() == T_symbol, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a symbol." ) );
T token;
wxString tmp;
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
wxString error;
wxString libName;
SCH_FIELD* field;
std::unique_ptr<SCH_COMPONENT> symbol( new SCH_COMPONENT() );
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
TRANSFORM transform;
std::set<int> fieldIDsRead;
m_fieldId = MANDATORY_FIELDS;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
case T_lib_name:
{
LIB_ID libId;
token = NextTok();
if( !IsSymbol( token ) )
{
error.Printf( _( "Invalid symbol library name in\nfile: \"%s\"\n"
"line: %d\noffset: %d" ),
CurSource().c_str(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
libName = FromUTF8();
NeedRIGHT();
break;
}
case T_lib_id:
{
token = NextTok();
if( !IsSymbol( token ) && token != T_NUMBER )
Expecting( "symbol|number" );
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
LIB_ID libId;
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
if( libId.Parse( FromUTF8(), LIB_ID::ID_SCH ) >= 0 )
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
error.Printf( _( "Invalid symbol library ID in\nfile: \"%s\"\nline: %d\n"
"offset: %d" ),
GetChars( CurSource() ), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
symbol->SetLibId( libId );
NeedRIGHT();
break;
}
case T_at:
symbol->SetPosition( parseXY() );
switch( static_cast<int>( parseDouble( "symbol orientation" ) ) )
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
case 0: transform = TRANSFORM(); break;
case 90: transform = TRANSFORM( 0, -1, -1, 0 ); break;
case 180: transform = TRANSFORM( -1, 0, 0, 1 ); break;
case 270: transform = TRANSFORM( 0, 1, 1, 0 ); break;
default: Expecting( "0, 90, 180, or 270" );
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
symbol->SetTransform( transform );
NeedRIGHT();
break;
case T_mirror:
token = NextTok();
if( token == T_x )
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
symbol->SetOrientation( CMP_MIRROR_X );
else if( token == T_y )
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
symbol->SetOrientation( CMP_MIRROR_Y );
else
Expecting( "x or y" );
NeedRIGHT();
break;
case T_unit:
symbol->SetUnit( parseInt( "symbol unit" ) );
NeedRIGHT();
break;
case T_convert:
symbol->SetConvert( parseInt( "symbol convert" ) );
NeedRIGHT();
break;
case T_in_bom:
symbol->SetIncludeInBom( parseBool() );
NeedRIGHT();
break;
case T_on_board:
symbol->SetIncludeOnBoard( parseBool() );
NeedRIGHT();
break;
case T_uuid:
NeedSYMBOL();
const_cast<KIID&>( symbol->m_Uuid ) = KIID( FromUTF8() );
NeedRIGHT();
break;
case T_property:
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
// The field parent symbol must be set and it's orientation must be set before
// the field positions are set.
field = parseSchField( symbol.get() );
// It would appear that at some point we allowed duplicate ids to slip through
// when writing files. The easiest (and most complete) solution is to disallow
// multiple instances of the same id (for all files since the source of the error
// *might* in fact be hand-edited files).
//
// While no longer used, -1 is still a valid id for user fields and will
// get written out as the next unused number on save.
if( fieldIDsRead.count( field->GetId() ) )
field->SetId( -1 );
else
fieldIDsRead.insert( field->GetId() );
// Set the default symbol reference prefix.
if( field->GetId() == REFERENCE )
{
wxString refDesignator = field->GetText();
refDesignator.Replace( "~", " " );
wxString prefix = refDesignator;
while( prefix.Length() )
{
if( ( prefix.Last() < '0' || prefix.Last() > '9') && prefix.Last() != '?' )
break;
prefix.RemoveLast();
}
// Avoid a prefix containing trailing/leading spaces
prefix.Trim( true );
prefix.Trim( false );
if( prefix.IsEmpty() )
symbol->SetPrefix( wxString( "U" ) );
else
symbol->SetPrefix( prefix );
}
if( symbol->GetField( field->GetId() ) )
*symbol->GetField( field->GetId() ) = *field;
else
symbol->AddField( *field );
delete field;
break;
}
case T_pin:
{
SCH_PIN* pin = new SCH_PIN( nullptr, symbol.get() );
NeedSYMBOL();
pin->SetNumber( FromUTF8() );
token = NextTok();
if( token == T_alternate )
{
NeedSYMBOL();
pin->SetAlt( FromUTF8() );
NeedRIGHT();
}
else
{
Expecting( "alternate" );
}
symbol->GetPins().push_back( pin );
NeedRIGHT();
}
break;
default:
Expecting( "lib_id, lib_name, at, mirror, uuid, property, pin, or instances" );
}
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
if( !libName.IsEmpty() && ( symbol->GetLibId().Format().wx_str() != libName ) )
symbol->SetSchSymbolLibraryName( libName );
// Ensure edit/status flags are cleared after these initializations:
symbol->ClearFlags();
return symbol.release();
}
SCH_BITMAP* SCH_SEXPR_PARSER::parseImage()
{
wxCHECK_MSG( CurTok() == T_image, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as an image." ) );
T token;
std::unique_ptr<SCH_BITMAP> bitmap( new SCH_BITMAP() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
bitmap->SetPosition( parseXY() );
NeedRIGHT();
break;
case T_scale:
bitmap->GetImage()->SetScale( parseDouble( "image scale factor" ) );
if( !std::isnormal( bitmap->GetImage()->GetScale() ) )
bitmap->GetImage()->SetScale( 1.0 );
NeedRIGHT();
break;
case T_data:
{
token = NextTok();
wxString data;
// Reserve 128K because most image files are going to be larger than the default
// 1K that wxString reserves.
data.reserve( 1 << 17 );
while( token != T_RIGHT )
{
if( !IsSymbol( token ) )
Expecting( "base64 image data" );
data += FromUTF8();
token = NextTok();
}
wxMemoryBuffer buffer = wxBase64Decode( data );
wxMemoryOutputStream stream( buffer.GetData(), buffer.GetBufSize() );
wxImage* image = new wxImage();
wxMemoryInputStream istream( stream );
image->LoadFile( istream, wxBITMAP_TYPE_PNG );
bitmap->GetImage()->SetImage( image );
bitmap->GetImage()->SetBitmap( new wxBitmap( *image ) );
break;
}
default:
Expecting( "at, scale, or data" );
}
}
return bitmap.release();
}
SCH_SHEET* SCH_SEXPR_PARSER::parseSheet()
{
wxCHECK_MSG( CurTok() == T_sheet, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a sheet." ) );
T token;
STROKE_PARAMS stroke;
FILL_PARAMS fill;
SCH_FIELD* field;
std::vector<SCH_FIELD> fields;
std::unique_ptr<SCH_SHEET> sheet( new SCH_SHEET() );
std::set<int> fieldIDsRead;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
sheet->SetPosition( parseXY() );
NeedRIGHT();
break;
case T_size:
{
wxSize size;
size.SetWidth( parseInternalUnits( "sheet width" ) );
size.SetHeight( parseInternalUnits( "sheet height" ) );
sheet->SetSize( size );
NeedRIGHT();
break;
}
case T_stroke:
parseStroke( stroke );
sheet->SetBorderWidth( stroke.GetWidth() );
sheet->SetBorderColor( stroke.GetColor() );
break;
case T_fill:
parseFill( fill );
sheet->SetBackgroundColor( fill.m_Color );
break;
case T_uuid:
NeedSYMBOL();
const_cast<KIID&>( sheet->m_Uuid ) = KIID( FromUTF8() );
NeedRIGHT();
break;
case T_property:
field = parseSchField( sheet.get() );
if( m_requiredVersion <= 20200310 )
{
// Earlier versions had the wrong ids (and names) saved for sheet fields.
// Fortunately they only saved the sheetname and sheetfilepath (and always
// in that order), so we can hack in a recovery.
if( fields.empty() )
field->SetId( SHEETNAME );
else
field->SetId( SHEETFILENAME );
}
// It would appear the problem persists past 20200310, but this time with the
// earlier ids being re-used for later (user) fields. The easiest (and most
// complete) solution is to disallow multiple instances of the same id (for all
// files since the source of the error *might* in fact be hand-edited files).
//
// While no longer used, -1 is still a valid id for user fields and will
// get written out as the next unused number on save.
if( fieldIDsRead.count( field->GetId() ) )
field->SetId( -1 );
else
fieldIDsRead.insert( field->GetId() );
fields.emplace_back( *field );
delete field;
break;
case T_pin:
sheet->AddPin( parseSchSheetPin( sheet.get() ) );
break;
default:
Expecting( "at, size, stroke, background, uuid, property, or pin" );
}
}
sheet->SetFields( fields );
return sheet.release();
}
SCH_JUNCTION* SCH_SEXPR_PARSER::parseJunction()
{
wxCHECK_MSG( CurTok() == T_junction, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a junction." ) );
T token;
std::unique_ptr<SCH_JUNCTION> junction( new SCH_JUNCTION() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
junction->SetPosition( parseXY() );
NeedRIGHT();
break;
case T_diameter:
junction->SetDiameter( parseInternalUnits( "junction diameter" ) );
NeedRIGHT();
break;
case T_color:
{
COLOR4D color;
color.r = parseInt( "red" ) / 255.0;
color.g = parseInt( "green" ) / 255.0;
color.b = parseInt( "blue" ) / 255.0;
color.a = Clamp( parseDouble( "alpha" ), 0.0, 1.0 );
junction->SetColor( color );
NeedRIGHT();
break;
}
default:
Expecting( "at" );
}
}
return junction.release();
}
SCH_NO_CONNECT* SCH_SEXPR_PARSER::parseNoConnect()
{
wxCHECK_MSG( CurTok() == T_no_connect, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a no connect." ) );
T token;
std::unique_ptr<SCH_NO_CONNECT> no_connect( new SCH_NO_CONNECT() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
no_connect->SetPosition( parseXY() );
NeedRIGHT();
break;
default:
Expecting( "at" );
}
}
return no_connect.release();
}
SCH_BUS_WIRE_ENTRY* SCH_SEXPR_PARSER::parseBusEntry()
{
wxCHECK_MSG( CurTok() == T_bus_entry, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a bus entry." ) );
T token;
STROKE_PARAMS stroke;
std::unique_ptr<SCH_BUS_WIRE_ENTRY> busEntry( new SCH_BUS_WIRE_ENTRY() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
busEntry->SetPosition( parseXY() );
NeedRIGHT();
break;
case T_size:
{
wxSize size;
size.SetWidth( parseInternalUnits( "bus entry height" ) );
size.SetHeight( parseInternalUnits( "bus entry width" ) );
busEntry->SetSize( size );
NeedRIGHT();
break;
}
case T_stroke:
parseStroke( stroke );
busEntry->SetStroke( stroke );
break;
default:
Expecting( "at, size, or stroke" );
}
}
return busEntry.release();
}
SCH_LINE* SCH_SEXPR_PARSER::parseLine()
{
T token;
STROKE_PARAMS stroke;
std::unique_ptr<SCH_LINE> line( new SCH_LINE() );
switch( CurTok() )
{
case T_polyline: line->SetLayer( LAYER_NOTES ); break;
case T_wire: line->SetLayer( LAYER_WIRE ); break;
case T_bus: line->SetLayer( LAYER_BUS ); break;
default:
wxCHECK_MSG( false, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a line." ) );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_pts:
NeedLEFT();
token = NextTok();
if( token != T_xy )
Expecting( "xy" );
line->SetStartPoint( parseXY() );
NeedRIGHT();
NeedLEFT();
token = NextTok();
if( token != T_xy )
Expecting( "xy" );
line->SetEndPoint( parseXY() );
NeedRIGHT();
NeedRIGHT();
break;
case T_stroke:
parseStroke( stroke );
line->SetStroke( stroke );
break;
default:
Expecting( "at or stroke" );
}
}
return line.release();
}
SCH_TEXT* SCH_SEXPR_PARSER::parseSchText()
{
T token;
std::unique_ptr<SCH_TEXT> text;
switch( CurTok() )
{
case T_text: text.reset( new SCH_TEXT ); break;
case T_label: text.reset( new SCH_LABEL ); break;
case T_global_label: text.reset( new SCH_GLOBALLABEL ); break;
case T_hierarchical_label: text.reset( new SCH_HIERLABEL ); break;
default:
wxCHECK_MSG( false, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as text." ) );
}
NeedSYMBOL();
text->SetText( FromUTF8() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
{
text->SetPosition( parseXY() );
switch( static_cast<int>( parseDouble( "text angle" ) ) )
{
case 0: text->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT ); break;
case 90: text->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP ); break;
case 180: text->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT ); break;
case 270: text->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM ); break;
default:
wxFAIL;
text->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
break;
}
NeedRIGHT();
break;
}
case T_shape:
{
if( text->Type() == SCH_TEXT_T || text->Type() == SCH_LABEL_T )
Unexpected( T_shape );
token = NextTok();
switch( token )
{
case T_input: text->SetShape( PINSHEETLABEL_SHAPE::PS_INPUT ); break;
case T_output: text->SetShape( PINSHEETLABEL_SHAPE::PS_OUTPUT ); break;
case T_bidirectional: text->SetShape( PINSHEETLABEL_SHAPE::PS_BIDI ); break;
case T_tri_state: text->SetShape( PINSHEETLABEL_SHAPE::PS_TRISTATE ); break;
case T_passive: text->SetShape( PINSHEETLABEL_SHAPE::PS_UNSPECIFIED ); break;
default:
Expecting( "input, output, bidirectional, tri_state, or passive" );
}
NeedRIGHT();
break;
}
case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( text.get() ) );
break;
default:
Expecting( "at, shape, or effects" );
}
}
return text.release();
}
void SCH_SEXPR_PARSER::parseBusAlias( SCH_SCREEN* aScreen )
{
wxCHECK_RET( CurTok() == T_bus_alias,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a bus alias." ) );
wxCHECK( aScreen, /* void */ );
T token;
auto busAlias = std::make_shared< BUS_ALIAS >( aScreen );
NeedSYMBOL();
busAlias->SetName( FromUTF8() );
NeedLEFT();
token = NextTok();
if( token != T_members )
Expecting( "members" );
token = NextTok();
while( token != T_RIGHT )
{
if( !IsSymbol( token ) )
Expecting( "quoted string" );
busAlias->AddMember( FromUTF8() );
token = NextTok();
}
NeedRIGHT();
aScreen->AddBusAlias( busAlias );
}