Initial commit of footprint library table code.
This commit is contained in:
parent
819404614a
commit
77e1a4c03c
|
@ -1,6 +1,8 @@
|
||||||
common/netlist_keywords.*
|
common/netlist_keywords.*
|
||||||
common/netlist_lexer.h
|
common/netlist_lexer.h
|
||||||
common/pcb_plot_params_lexer.h
|
common/pcb_plot_params_lexer.h
|
||||||
|
common/fp_lib_table_keywords.*
|
||||||
|
include/fp_lib_table_lexer.h
|
||||||
include/netlist_lexer.h
|
include/netlist_lexer.h
|
||||||
eeschema/cmp_library_lexer.h
|
eeschema/cmp_library_lexer.h
|
||||||
eeschema/cmp_library_keywords.*
|
eeschema/cmp_library_keywords.*
|
||||||
|
|
|
@ -16,7 +16,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
|
||||||
# KiCad build options should be added below.
|
# KiCad build options should be added below.
|
||||||
#
|
#
|
||||||
# If you add a new build option, please add it's state to the CopyVersionInfoToClipboard()
|
# If you add a new build option, please add it's state to the CopyVersionInfoToClipboard()
|
||||||
# function in common/basicframe.cpp so that build option settings can be includeed in bug
|
# function in common/basicframe.cpp so that build option settings can be included in bug
|
||||||
# reports.
|
# reports.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -162,8 +162,6 @@ endif(KICAD_SCRIPTING_MODULES)
|
||||||
|
|
||||||
if(KICAD_SCRIPTING_WXPYTHON)
|
if(KICAD_SCRIPTING_WXPYTHON)
|
||||||
add_definitions(-DKICAD_SCRIPTING_WXPYTHON)
|
add_definitions(-DKICAD_SCRIPTING_WXPYTHON)
|
||||||
|
|
||||||
|
|
||||||
endif(KICAD_SCRIPTING_WXPYTHON)
|
endif(KICAD_SCRIPTING_WXPYTHON)
|
||||||
|
|
||||||
if(USE_WX_GRAPHICS_CONTEXT)
|
if(USE_WX_GRAPHICS_CONTEXT)
|
||||||
|
@ -171,7 +169,7 @@ if(USE_WX_GRAPHICS_CONTEXT)
|
||||||
endif(USE_WX_GRAPHICS_CONTEXT)
|
endif(USE_WX_GRAPHICS_CONTEXT)
|
||||||
|
|
||||||
# Allow user to override the default settings for adding images to menu items. By default
|
# Allow user to override the default settings for adding images to menu items. By default
|
||||||
# images in menu items are enabled on all plaforms except OSX. This can be over ridden by
|
# images in menu items are enabled on all platforms except OSX. This can be over ridden by
|
||||||
# defining -DUSE_IMAGES_IN_MENUS=ON/OFF to force the preferred behavior.
|
# defining -DUSE_IMAGES_IN_MENUS=ON/OFF to force the preferred behavior.
|
||||||
if(NOT DEFINED USE_IMAGES_IN_MENUS)
|
if(NOT DEFINED USE_IMAGES_IN_MENUS)
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
|
|
|
@ -124,6 +124,9 @@ set(PCB_COMMON_SRCS
|
||||||
pcb_plot_params_keywords.cpp
|
pcb_plot_params_keywords.cpp
|
||||||
pcb_keywords.cpp
|
pcb_keywords.cpp
|
||||||
../pcbnew/pcb_parser.cpp
|
../pcbnew/pcb_parser.cpp
|
||||||
|
fp_lib_table_keywords.cpp
|
||||||
|
fp_lib_id.cpp
|
||||||
|
fp_lib_table.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,9 +158,15 @@ make_lexer(
|
||||||
make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/pcb.keywords
|
make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/pcb.keywords
|
||||||
${PROJECT_SOURCE_DIR}/include/pcb_lexer.h
|
${PROJECT_SOURCE_DIR}/include/pcb_lexer.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/pcb_keywords.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/pcb_keywords.cpp
|
||||||
PCB
|
PCB_FILE_T
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# auto-generate pcbnew s-expression footprint library table code.
|
||||||
|
make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/fp_lib_table.keywords
|
||||||
|
${PROJECT_SOURCE_DIR}/include/fp_lib_table_lexer.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/fp_lib_table_keywords.cpp
|
||||||
|
FP_LIB_TABLE_T
|
||||||
|
)
|
||||||
|
|
||||||
# The dsntest may not build properly using MS Visual Studio.
|
# The dsntest may not build properly using MS Visual Studio.
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
|
|
|
@ -0,0 +1,413 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <wx/wx.h> // _()
|
||||||
|
|
||||||
|
#include <fp_lib_id.h>
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool isDigit( char c )
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* EndsWithRev( const char* start, const char* tail, char separator )
|
||||||
|
{
|
||||||
|
bool sawDigit = false;
|
||||||
|
|
||||||
|
while( tail > start && isDigit( *--tail ) )
|
||||||
|
{
|
||||||
|
sawDigit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if sawDigit, tail points to the 'v' here.
|
||||||
|
|
||||||
|
if( sawDigit && tail-3 >= start )
|
||||||
|
{
|
||||||
|
tail -= 3;
|
||||||
|
|
||||||
|
if( tail[0]==separator && tail[1]=='r' && tail[2]=='e' && tail[3]=='v' )
|
||||||
|
{
|
||||||
|
return tail+1; // omit separator, return "revN[N..]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int RevCmp( const char* s1, const char* s2 )
|
||||||
|
{
|
||||||
|
int r = strncmp( s1, s2, 3 );
|
||||||
|
|
||||||
|
if( r || strlen(s1)<4 || strlen(s2)<4 )
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnum1 = atoi( s1+3 );
|
||||||
|
int rnum2 = atoi( s2+3 );
|
||||||
|
|
||||||
|
return -(rnum1 - rnum2); // swap the sign, higher revs first
|
||||||
|
}
|
||||||
|
|
||||||
|
//----<Policy and field test functions>-------------------------------------
|
||||||
|
|
||||||
|
// These all return -1 on success, or >= 0 if there is an error at a
|
||||||
|
// particular character offset into their respective arguments. If >=0,
|
||||||
|
// then that return value gives the character offset of the error.
|
||||||
|
|
||||||
|
|
||||||
|
static inline int okLogical( const std::string& aField )
|
||||||
|
{
|
||||||
|
// std::string::npos is largest positive number, casting to int makes it -1.
|
||||||
|
// Returning that means success.
|
||||||
|
return int( aField.find_first_of( ":/" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int okBase( const std::string& aField )
|
||||||
|
{
|
||||||
|
int offset = int( aField.find_first_of( ":/" ) );
|
||||||
|
|
||||||
|
if( offset != -1 )
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
// cannot be empty
|
||||||
|
if( !aField.size() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return offset; // ie. -1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int okRevision( const std::string& aField )
|
||||||
|
{
|
||||||
|
char rev[32]; // C string for speed
|
||||||
|
|
||||||
|
if( aField.size() >= 4 )
|
||||||
|
{
|
||||||
|
strcpy( rev, "x/" );
|
||||||
|
strcat( rev, aField.c_str() );
|
||||||
|
|
||||||
|
if( EndsWithRev( rev, rev + strlen(rev) ) == rev+2 )
|
||||||
|
return -1; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // first character position "is in error", is best we can do.
|
||||||
|
}
|
||||||
|
|
||||||
|
//----</Policy and field test functions>-------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
void FP_LIB_ID::clear()
|
||||||
|
{
|
||||||
|
logical.clear();
|
||||||
|
baseName.clear();
|
||||||
|
footprintName.clear();
|
||||||
|
revision.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FP_LIB_ID::Parse( const std::string& aId )
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
const char* rev = EndsWithRev( aId );
|
||||||
|
size_t revNdx;
|
||||||
|
size_t partNdx;
|
||||||
|
size_t baseNdx;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
//=====<revision>=========================================
|
||||||
|
if( rev )
|
||||||
|
{
|
||||||
|
revNdx = rev - aId.c_str();
|
||||||
|
|
||||||
|
// no need to check revision, EndsWithRev did that.
|
||||||
|
revision = aId.substr( revNdx );
|
||||||
|
--revNdx; // back up to omit the '/' which preceeds the rev
|
||||||
|
}
|
||||||
|
else
|
||||||
|
revNdx = aId.size();
|
||||||
|
|
||||||
|
//=====<logical>==========================================
|
||||||
|
if( ( partNdx = aId.find( ':' ) ) != aId.npos )
|
||||||
|
{
|
||||||
|
offset = SetLogicalLib( aId.substr( 0, partNdx ) );
|
||||||
|
if( offset > -1 )
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
++partNdx; // skip ':'
|
||||||
|
}
|
||||||
|
else
|
||||||
|
partNdx = 0;
|
||||||
|
|
||||||
|
//=====<baseName>==========================================
|
||||||
|
offset = SetBaseName( aId.substr( baseNdx, revNdx - baseNdx ) );
|
||||||
|
|
||||||
|
if( offset > -1 )
|
||||||
|
{
|
||||||
|
return offset + baseNdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FP_LIB_ID::FP_LIB_ID( const std::string& aId ) throw( PARSE_ERROR )
|
||||||
|
{
|
||||||
|
int offset = Parse( aId );
|
||||||
|
|
||||||
|
if( offset != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR( _( "Illegal character found in FP_LIB_ID string" ),
|
||||||
|
wxString::FromUTF8( aId.c_str() ),
|
||||||
|
aId.c_str(),
|
||||||
|
0,
|
||||||
|
offset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FP_LIB_ID::SetLogicalLib( const std::string& aLogical )
|
||||||
|
{
|
||||||
|
int offset = okLogical( aLogical );
|
||||||
|
|
||||||
|
if( offset == -1 )
|
||||||
|
{
|
||||||
|
logical = aLogical;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FP_LIB_ID::SetBaseName( const std::string& aBaseName )
|
||||||
|
{
|
||||||
|
int offset = okBase( aBaseName );
|
||||||
|
|
||||||
|
if( offset == -1 )
|
||||||
|
{
|
||||||
|
baseName = aBaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FP_LIB_ID::SetFootprintName( const std::string& aFootprintName )
|
||||||
|
{
|
||||||
|
std::string base;
|
||||||
|
int offset;
|
||||||
|
int separation = int( aFootprintName.find_first_of( "/" ) );
|
||||||
|
|
||||||
|
if( separation != -1 )
|
||||||
|
{
|
||||||
|
base = aFootprintName.substr( separation+1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base = aFootprintName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (offset = SetBaseName( base )) != -1 )
|
||||||
|
{
|
||||||
|
return offset + separation + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FP_LIB_ID::SetRevision( const std::string& aRevision )
|
||||||
|
{
|
||||||
|
int offset = okRevision( aRevision );
|
||||||
|
|
||||||
|
if( offset == -1 )
|
||||||
|
{
|
||||||
|
revision = aRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string FP_LIB_ID::Format() const
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
if( logical.size() )
|
||||||
|
{
|
||||||
|
ret += logical;
|
||||||
|
ret += ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += baseName;
|
||||||
|
|
||||||
|
if( revision.size() )
|
||||||
|
{
|
||||||
|
ret += '/';
|
||||||
|
ret += revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string FP_LIB_ID::GetFootprintNameAndRev() const
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
ret += baseName;
|
||||||
|
|
||||||
|
if( revision.size() )
|
||||||
|
{
|
||||||
|
ret += '/';
|
||||||
|
ret += revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string FP_LIB_ID::Format( const std::string& aLogicalLib, const std::string& aFootprintName,
|
||||||
|
const std::string& aRevision )
|
||||||
|
throw( PARSE_ERROR )
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if( aLogicalLib.size() )
|
||||||
|
{
|
||||||
|
offset = okLogical( aLogicalLib );
|
||||||
|
|
||||||
|
if( offset != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR( _( "Illegal character found in logical lib name" ),
|
||||||
|
wxString::FromUTF8( aLogicalLib.c_str() ),
|
||||||
|
aLogicalLib.c_str(),
|
||||||
|
0,
|
||||||
|
offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += aLogicalLib;
|
||||||
|
ret += ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string base;
|
||||||
|
|
||||||
|
int separation = int( aFootprintName.find_first_of( "/" ) );
|
||||||
|
|
||||||
|
if( separation != -1 )
|
||||||
|
{
|
||||||
|
base = aFootprintName.substr( separation+1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base = aFootprintName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( (offset = okBase( base )) != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR( _( "Illegal character found in base name" ),
|
||||||
|
wxString::FromUTF8( aRevision.c_str() ),
|
||||||
|
aRevision.c_str(),
|
||||||
|
0,
|
||||||
|
offset + separation + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += base;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aRevision.size() )
|
||||||
|
{
|
||||||
|
offset = okRevision( aRevision );
|
||||||
|
|
||||||
|
if( offset != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR( _( "Illegal character found in revision" ),
|
||||||
|
wxString::FromUTF8( aRevision.c_str() ),
|
||||||
|
aRevision.c_str(),
|
||||||
|
0,
|
||||||
|
offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += '/';
|
||||||
|
ret += aRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0 && defined(DEBUG)
|
||||||
|
|
||||||
|
// build this with Debug CMAKE_BUILD_TYPE
|
||||||
|
|
||||||
|
void FP_LIB_ID::Test()
|
||||||
|
{
|
||||||
|
static const char* lpids[] = {
|
||||||
|
"/R/rev0",
|
||||||
|
"passives/R/rev2",
|
||||||
|
":passives/R/rev3",
|
||||||
|
"C/rev22",
|
||||||
|
"passives/C22",
|
||||||
|
"R",
|
||||||
|
"me:R",
|
||||||
|
// most difficult:
|
||||||
|
"me:/R/rev0",
|
||||||
|
"me:R/rev0",
|
||||||
|
};
|
||||||
|
|
||||||
|
for( unsigned i=0; i<sizeof(lpids)/sizeof(lpids[0]); ++i )
|
||||||
|
{
|
||||||
|
// test some round tripping
|
||||||
|
|
||||||
|
FP_LIB_ID lpid( lpids[i] ); // parse
|
||||||
|
|
||||||
|
// format
|
||||||
|
printf( "input:'%s' full:'%s' base:'%s' footprintName:'%s' rev:'%s'\n",
|
||||||
|
lpids[i],
|
||||||
|
lpid.Format().c_str(),
|
||||||
|
lpid.GetBaseName().c_str(),
|
||||||
|
lpid.GetFootprintName().c_str(),
|
||||||
|
lpid.GetRevision().c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char** argv )
|
||||||
|
{
|
||||||
|
FP_LIB_ID::Test();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,312 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||||
|
* Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <io_mgr.h>
|
||||||
|
|
||||||
|
#include <fp_lib_table_lexer.h>
|
||||||
|
#include <fp_lib_table.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace FP_LIB_TABLE_T;
|
||||||
|
|
||||||
|
|
||||||
|
FP_LIB_TABLE::FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable ) :
|
||||||
|
fallBack( aFallBackTable )
|
||||||
|
{
|
||||||
|
// not copying fall back, simply search aFallBackTable separately
|
||||||
|
// if "logicalName not found".
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR )
|
||||||
|
{
|
||||||
|
T tok;
|
||||||
|
|
||||||
|
while( ( tok = in->NextTok() ) != T_RIGHT )
|
||||||
|
{
|
||||||
|
// (lib (name "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS"))
|
||||||
|
|
||||||
|
if( tok == T_EOF )
|
||||||
|
in->Expecting( T_RIGHT );
|
||||||
|
|
||||||
|
if( tok != T_LEFT )
|
||||||
|
in->Expecting( T_LEFT );
|
||||||
|
|
||||||
|
if( ( tok = in->NextTok() ) != T_fp_lib )
|
||||||
|
in->Expecting( T_fp_lib );
|
||||||
|
|
||||||
|
// (name "LOGICAL_NAME")
|
||||||
|
in->NeedLEFT();
|
||||||
|
|
||||||
|
if( ( tok = in->NextTok() ) != T_name )
|
||||||
|
in->Expecting( T_name );
|
||||||
|
|
||||||
|
in->NeedSYMBOLorNUMBER();
|
||||||
|
|
||||||
|
std::auto_ptr<ROW> row( new ROW( this ) );
|
||||||
|
|
||||||
|
row->SetLogicalName( in->CurText() );
|
||||||
|
|
||||||
|
in->NeedRIGHT();
|
||||||
|
|
||||||
|
// (type "TYPE")
|
||||||
|
in->NeedLEFT();
|
||||||
|
|
||||||
|
if( ( tok = in->NextTok() ) != T_type )
|
||||||
|
in->Expecting( T_type );
|
||||||
|
|
||||||
|
in->NeedSYMBOLorNUMBER();
|
||||||
|
|
||||||
|
row->SetType( in->CurText() );
|
||||||
|
|
||||||
|
in->NeedRIGHT();
|
||||||
|
|
||||||
|
// (uri "FULL_URI")
|
||||||
|
in->NeedLEFT();
|
||||||
|
|
||||||
|
if( ( tok = in->NextTok() ) != T_full_uri )
|
||||||
|
in->Expecting( T_full_uri );
|
||||||
|
|
||||||
|
in->NeedSYMBOLorNUMBER();
|
||||||
|
|
||||||
|
row->SetFullURI( in->CurText() );
|
||||||
|
|
||||||
|
in->NeedRIGHT();
|
||||||
|
|
||||||
|
// (options "OPTIONS")
|
||||||
|
in->NeedLEFT();
|
||||||
|
|
||||||
|
if( ( tok = in->NextTok() ) != T_options )
|
||||||
|
in->Expecting( T_options );
|
||||||
|
|
||||||
|
in->NeedSYMBOLorNUMBER();
|
||||||
|
|
||||||
|
row->SetOptions( in->CurText() );
|
||||||
|
|
||||||
|
in->NeedRIGHT();
|
||||||
|
in->NeedRIGHT(); // terminate the (lib..)
|
||||||
|
|
||||||
|
// all logicalNames within this table fragment must be unique, so we do not
|
||||||
|
// use doReplace in InsertRow(). However a fallBack table can have a
|
||||||
|
// conflicting logicalName and ours will supercede that one since in
|
||||||
|
// FindLib() we search this table before any fall back.
|
||||||
|
if( !InsertRow( row ) )
|
||||||
|
{
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
msg += '\'';
|
||||||
|
msg += row->logicalName;
|
||||||
|
msg += '\'';
|
||||||
|
msg += " is a duplicate logical footprint library name";
|
||||||
|
THROW_IO_ERROR( msg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FP_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
out->Print( nestLevel, "(fp_lib_table\n" );
|
||||||
|
|
||||||
|
for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
|
||||||
|
it->second->Format( out, nestLevel+1 );
|
||||||
|
|
||||||
|
out->Print( nestLevel, ")\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
out->Print( nestLevel, "(lib (logical %s)(type %s)(full_uri %s)(options %s))\n",
|
||||||
|
out->Quotes( logicalName ).c_str(),
|
||||||
|
out->Quotes( type ).c_str(),
|
||||||
|
out->Quotes( uri ).c_str(),
|
||||||
|
out->Quotes( options ).c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string> FP_LIB_TABLE::GetLogicalLibs()
|
||||||
|
{
|
||||||
|
// Only return unique logical library names. Use std::set::insert() to
|
||||||
|
// quietly reject any duplicates, which can happen when encountering a duplicate
|
||||||
|
// logical lib name from one of the fall back table(s).
|
||||||
|
|
||||||
|
std::set<std::string> unique;
|
||||||
|
std::vector<std::string> ret;
|
||||||
|
const FP_LIB_TABLE* cur = this;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
for( ROWS_CITER it = cur->rows.begin(); it!=cur->rows.end(); ++it )
|
||||||
|
{
|
||||||
|
unique.insert( it->second->logicalName );
|
||||||
|
}
|
||||||
|
|
||||||
|
} while( ( cur = cur->fallBack ) != 0 );
|
||||||
|
|
||||||
|
// return a sorted, unique set of logical lib name std::vector<std::string> to caller
|
||||||
|
for( std::set<std::string>::const_iterator it = unique.begin(); it!=unique.end(); ++it )
|
||||||
|
ret.push_back( *it );
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId )
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
PLUGIN* plugin = lookupLib( aFootprintId );
|
||||||
|
|
||||||
|
return plugin->FootprintLoad( wxString( aFootprintId.GetBaseName().c_str() ),
|
||||||
|
wxString( aFootprintId.GetLogicalLib().c_str() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PLUGIN* FP_LIB_TABLE::lookupLib( const FP_LIB_ID& aFootprintId )
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
if( aFootprintId.GetLogicalLib().size() )
|
||||||
|
{
|
||||||
|
ROW* row = FindRow( aFootprintId.GetLogicalLib() );
|
||||||
|
|
||||||
|
if( !row )
|
||||||
|
{
|
||||||
|
std::string msg = "lib table contains no logical lib '";
|
||||||
|
msg += aFootprintId.GetLogicalLib();
|
||||||
|
msg += '\'';
|
||||||
|
THROW_IO_ERROR( msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !row->lib )
|
||||||
|
{
|
||||||
|
loadLib( row );
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( row->lib ); // fix loadLib() to throw if cannot load
|
||||||
|
|
||||||
|
return row->lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string msg = "lookupLib() requires logicalLibName";
|
||||||
|
THROW_IO_ERROR( msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FP_LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
assert( !aRow->lib ); // caller should know better.
|
||||||
|
|
||||||
|
const std::string& type = aRow->GetType();
|
||||||
|
|
||||||
|
if( !type.compare( "dir" ) )
|
||||||
|
{
|
||||||
|
// @todo Look up plug in here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
else if( !type.compare( "schematic" ) )
|
||||||
|
{
|
||||||
|
// @todo code and load SCHEMATIC_LIB_SOURCE
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !type.compare( "subversion" ) )
|
||||||
|
{
|
||||||
|
// @todo code and load SVN_LIB_SOURCE
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !type.compare( "http" ) )
|
||||||
|
{
|
||||||
|
// @todo code and load HTTP_LIB_SOURCE
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string msg = "cannot load unknown footprint library type: '";
|
||||||
|
msg += type;
|
||||||
|
msg += '\'';
|
||||||
|
THROW_IO_ERROR( msg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const std::string& aLogicalName ) const
|
||||||
|
{
|
||||||
|
// this function must be *super* fast, so therefore should not instantiate
|
||||||
|
// anything which would require using the heap. This function is the reason
|
||||||
|
// ptr_map<> was used instead of ptr_set<>, which would have required
|
||||||
|
// instantiating a ROW just to find a ROW.
|
||||||
|
const FP_LIB_TABLE* cur = this;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ROWS_CITER it = cur->rows.find( aLogicalName );
|
||||||
|
|
||||||
|
if( it != cur->rows.end() )
|
||||||
|
{
|
||||||
|
// reference: http://myitcorner.com/blog/?p=361
|
||||||
|
return (FP_LIB_TABLE::ROW*) it->second; // found
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found, search fall back table(s), if any
|
||||||
|
} while( ( cur = cur->fallBack ) != 0 );
|
||||||
|
|
||||||
|
return 0; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool FP_LIB_TABLE::InsertRow( std::auto_ptr<ROW>& aRow, bool doReplace )
|
||||||
|
{
|
||||||
|
// this does not need to be super fast.
|
||||||
|
|
||||||
|
ROWS_CITER it = rows.find( aRow->logicalName );
|
||||||
|
|
||||||
|
if( it == rows.end() )
|
||||||
|
{
|
||||||
|
// be careful here, key is needed because aRow can be
|
||||||
|
// release()ed before logicalName is captured.
|
||||||
|
const std::string& key = aRow->logicalName;
|
||||||
|
rows.insert( key, aRow );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( doReplace )
|
||||||
|
{
|
||||||
|
rows.erase( aRow->logicalName );
|
||||||
|
|
||||||
|
// be careful here, key is needed because aRow can be
|
||||||
|
// release()ed before logicalName is captured.
|
||||||
|
const std::string& key = aRow->logicalName;
|
||||||
|
rows.insert( key, aRow );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
fp_lib_table
|
||||||
|
name
|
||||||
|
type
|
||||||
|
kicad
|
||||||
|
legacy
|
||||||
|
eagle
|
||||||
|
full_uri
|
||||||
|
options
|
||||||
|
fp_lib
|
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FP_LIB_ID_H_
|
||||||
|
#define _FP_LIB_ID_H_
|
||||||
|
|
||||||
|
#include <richio.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FP_LIB_ID
|
||||||
|
* (aka GUID) is a Logical Part ID and consists of various portions much like a URI.
|
||||||
|
* It is a container for the separated portions of a logical part id std::string so they
|
||||||
|
* can be accessed individually. The various portions of an FP_LIB_ID are:
|
||||||
|
* logicalLibraryName, category, baseName, and revision. Only the baseName is
|
||||||
|
* mandatory. There is another construct called "footprintName" which consists of
|
||||||
|
* [category/]baseName. That is the category followed by a slash, but only if
|
||||||
|
* the category is not empty.
|
||||||
|
* <p>
|
||||||
|
* footprintName = [category/]baseName
|
||||||
|
* <p>
|
||||||
|
* Example FP_LIB_ID string:
|
||||||
|
* "smt:R_0805".
|
||||||
|
* <p>
|
||||||
|
* <ul>
|
||||||
|
* <li> "smt" is the logical library name.
|
||||||
|
* <li> "R" is the footprint name.
|
||||||
|
* <li> "rev6" is the revision, which is optional. If missing then its
|
||||||
|
* / delimiter should also not be present. A revision must begin with
|
||||||
|
* "rev" and be followed by at least one or more decimal digits.
|
||||||
|
* </ul>
|
||||||
|
* @author Dick Hollenbeck
|
||||||
|
*/
|
||||||
|
class FP_LIB_ID // aka GUID
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FP_LIB_ID() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor FP_LIB_ID
|
||||||
|
* takes \a aId string and parses it. A typical FP_LIB_ID string uses a logical
|
||||||
|
* library name followed by a footprint name.
|
||||||
|
* e.g.: "smt:R_0805", or
|
||||||
|
* e.g.: "mylib:R_0805"
|
||||||
|
*/
|
||||||
|
FP_LIB_ID( const std::string& aId ) throw( PARSE_ERROR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Parse
|
||||||
|
* [re-]stuffs this FP_LIB_ID with the information from @a aId.
|
||||||
|
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the
|
||||||
|
* character offset into aId at which an error was detected.
|
||||||
|
*/
|
||||||
|
int Parse( const std::string& aId );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetLogicalLib
|
||||||
|
* returns the logical library portion of a FP_LIB_ID. There is not Set accessor
|
||||||
|
* for this portion since it comes from the library table and is considered
|
||||||
|
* read only here.
|
||||||
|
*/
|
||||||
|
const std::string& GetLogicalLib() const
|
||||||
|
{
|
||||||
|
return logical;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetCategory
|
||||||
|
* overrides the logical lib name portion of the FP_LIB_ID to @a aLogical, and can be empty.
|
||||||
|
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the
|
||||||
|
* character offset into the parameter at which an error was detected, usually
|
||||||
|
* because it contained '/' or ':'.
|
||||||
|
*/
|
||||||
|
int SetLogicalLib( const std::string& aLogical );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetBaseName
|
||||||
|
* returns the part name without the category.
|
||||||
|
*/
|
||||||
|
const std::string& GetBaseName() const
|
||||||
|
{
|
||||||
|
return baseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetBaseName
|
||||||
|
* overrides the base name portion of the FP_LIB_ID to @a aBaseName
|
||||||
|
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the
|
||||||
|
* character offset into the parameter at which an error was detected, usually
|
||||||
|
* because it contained '/' or ':', or is blank.
|
||||||
|
*/
|
||||||
|
int SetBaseName( const std::string& aBaseName );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetFootprintName
|
||||||
|
* returns the part name, i.e. category/baseName without revision.
|
||||||
|
*/
|
||||||
|
const std::string& GetFootprintName() const
|
||||||
|
{
|
||||||
|
return footprintName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetFootprintNameAndRev
|
||||||
|
* returns the part name with revision if any, i.e. baseName[/revN..]
|
||||||
|
*/
|
||||||
|
std::string GetFootprintNameAndRev() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetFootprintName
|
||||||
|
* overrides the part name portion of the FP_LIB_ID to @a aFootprintName
|
||||||
|
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the
|
||||||
|
* character offset into the parameter at which an error was detected, usually
|
||||||
|
* because it contained more than one '/', or one or more ':', or is blank.
|
||||||
|
* A single '/' is allowed, since that is used to separate the category from the
|
||||||
|
* base name.
|
||||||
|
*/
|
||||||
|
int SetFootprintName( const std::string& aFootprintName );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetRevision
|
||||||
|
* returns the revision portion of the FP_LIB_ID.
|
||||||
|
*/
|
||||||
|
const std::string& GetRevision() const
|
||||||
|
{
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetRevision
|
||||||
|
* overrides the revision portion of the FP_LIB_ID to @a aRevision and must
|
||||||
|
* be in the form "rev<num>" where "<num>" is "1", "2", etc.
|
||||||
|
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the
|
||||||
|
* character offset into the parameter at which an error was detected,
|
||||||
|
* because it did not look like "rev23"
|
||||||
|
*/
|
||||||
|
int SetRevision( const std::string& aRevision );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Format
|
||||||
|
* returns the full text of the FP_LIB_ID.
|
||||||
|
*/
|
||||||
|
std::string Format() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Format
|
||||||
|
* returns a std::string in the proper format as an FP_LIB_ID for a combination of
|
||||||
|
* aLogicalLib, aFootprintName, and aRevision.
|
||||||
|
* @throw PARSE_ERROR if any of the pieces are illegal.
|
||||||
|
*/
|
||||||
|
static std::string Format( const std::string& aLogicalLib, const std::string& aFootprintName,
|
||||||
|
const std::string& aRevision="" )
|
||||||
|
throw( PARSE_ERROR );
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
static void Test();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string logical; ///< logical lib name or empty
|
||||||
|
std::string baseName; ///< without category
|
||||||
|
std::string revision; ///< "revN[N..]" or empty
|
||||||
|
std::string footprintName; ///< cannot be set directory, set via SetBaseName() & SetCategory()
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function EndsWithRev
|
||||||
|
* returns a pointer to the final string segment: "revN[N..]" or NULL if none.
|
||||||
|
* @param start is the beginning of string segment to test, the partname or
|
||||||
|
* any middle portion of it.
|
||||||
|
* @param tail is a pointer to the terminating nul, or one past inclusive end of
|
||||||
|
* segment, i.e. the string segment of interest is [start,tail)
|
||||||
|
* @param separator is the separating byte, expected: '.' or '/', depending on context.
|
||||||
|
*/
|
||||||
|
const char* EndsWithRev( const char* start, const char* tail, char separator = '/' );
|
||||||
|
|
||||||
|
static inline const char* EndsWithRev( const std::string& aFootprintName, char separator = '/' )
|
||||||
|
{
|
||||||
|
return EndsWithRev( aFootprintName.c_str(), aFootprintName.c_str()+aFootprintName.size(),
|
||||||
|
separator );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function RevCmp
|
||||||
|
* compares two rev strings in a way like strcmp() except that the highest numbered
|
||||||
|
* revision is considered first in the sort order. The function probably won't work
|
||||||
|
* unless you give it two rev strings.
|
||||||
|
* @param s1 is a rev string like "rev10"
|
||||||
|
* @param s2 is a rev string like "rev1".
|
||||||
|
* @return int - either negative, zero, or positive depending on whether the revision
|
||||||
|
* is greater, equal, or less on the left hand side.
|
||||||
|
*/
|
||||||
|
int RevCmp( const char* s1, const char* s2 );
|
||||||
|
|
||||||
|
#endif // _FP_LIB_ID_H_
|
|
@ -0,0 +1,379 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||||
|
* Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FP_LIB_TABLE_H_
|
||||||
|
#define _FP_LIB_TABLE_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <fp_lib_id.h>
|
||||||
|
|
||||||
|
#include <boost/ptr_container/ptr_map.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
class OUTPUTFORMATTER;
|
||||||
|
|
||||||
|
|
||||||
|
class MODULE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FP_LIB_TABLE
|
||||||
|
* holds FP_LIB_TABLE::ROW records, and can be searched based on logical library name.
|
||||||
|
* <p>
|
||||||
|
* This class owns the <b>footprint library table</b>, which is like fstab in concept and maps
|
||||||
|
* logical library name to the library URI, type, and options. It is heavily based on the SWEET
|
||||||
|
* parser work done by Dick Hollenbeck and can be seen in new/sch_lib_table.h. A footprint
|
||||||
|
* library table had the following columns:
|
||||||
|
* <ul>
|
||||||
|
* <li> Logical Library Name (Nickname)
|
||||||
|
* <li> Library Type, used to determine which plugin to load to access the library.
|
||||||
|
* <li> Library URI. The full URI to the library source, form dependent on Type.
|
||||||
|
* <li> Options, used for as yet to be defined information such as user names or passwords
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* The Library Type can be one of:
|
||||||
|
* <ul>
|
||||||
|
* <li> "file"
|
||||||
|
* <li> "ftp"
|
||||||
|
* <li> "http"
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* For now, the Library URI types needed to support the various types can be one of those
|
||||||
|
* shown below, which are typical of each type:
|
||||||
|
* <ul>
|
||||||
|
* <li> "file://C:/mylibdir"
|
||||||
|
* <li> "ftp://kicad.org/partlib/trunk"
|
||||||
|
* <li> "http://kicad.org/partlib"
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* The footprint library table is built up from several additive entries (table fragments),
|
||||||
|
* and the final table is a (conceptual) merging of the table fragments. Two
|
||||||
|
* anticipated sources of the entries are a personal table saved in the KiCad configuration
|
||||||
|
* and a project resident table that resides in project file. The project footprint table
|
||||||
|
* entries are considered a higher priority in the final dynamically assembled library table.
|
||||||
|
* An row in the project file contribution to the library table takes precedence over the
|
||||||
|
* personal table if there is a collision of logical library names. Otherwise, the entries
|
||||||
|
* simply combine without issue to make up the applicable library table.
|
||||||
|
*
|
||||||
|
* @author Wayne Stambaugh
|
||||||
|
*/
|
||||||
|
class FP_LIB_TABLE
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ROW
|
||||||
|
* holds a record identifying a footprint library accessed by the appropriate #PLUGIN
|
||||||
|
* object in the #FP_LIB_TABLE.
|
||||||
|
*/
|
||||||
|
class ROW
|
||||||
|
{
|
||||||
|
friend class FP_LIB_TABLE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetLogicalName
|
||||||
|
* returns the logical name of this library table row.
|
||||||
|
*/
|
||||||
|
const std::string& GetLogicalName() const
|
||||||
|
{
|
||||||
|
return logicalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetType
|
||||||
|
* returns the type of LIB represented by this record.
|
||||||
|
*/
|
||||||
|
const std::string& GetType() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetFullURI
|
||||||
|
* returns the full location specifying URI for the LIB.
|
||||||
|
*/
|
||||||
|
const std::string& GetFullURI() const
|
||||||
|
{
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetOptions
|
||||||
|
* returns the options string, which may hold a password or anything else needed to
|
||||||
|
* instantiate the underlying LIB_SOURCE.
|
||||||
|
*/
|
||||||
|
const std::string& GetOptions() const
|
||||||
|
{
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ROW()
|
||||||
|
{
|
||||||
|
delete lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Format
|
||||||
|
* serializes this object as utf8 text to an OUTPUTFORMATTER, and tries to
|
||||||
|
* make it look good using multiple lines and indentation.
|
||||||
|
* @param out is an #OUTPUTFORMATTER
|
||||||
|
* @param nestLevel is the indentation level to base all lines of the output.
|
||||||
|
* Actual indentation will be 2 spaces for each nestLevel.
|
||||||
|
*/
|
||||||
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) const
|
||||||
|
throw( IO_ERROR );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
ROW( FP_LIB_TABLE* aOwner ) :
|
||||||
|
owner( aOwner ),
|
||||||
|
lib( 0 )
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetLogicalName
|
||||||
|
* changes the logical name of this library, useful for an editor.
|
||||||
|
*/
|
||||||
|
void SetLogicalName( const std::string& aLogicalName )
|
||||||
|
{
|
||||||
|
logicalName = aLogicalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetType
|
||||||
|
* changes the type represented by this record.
|
||||||
|
*/
|
||||||
|
void SetType( const std::string& aType )
|
||||||
|
{
|
||||||
|
type = aType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetFullURI
|
||||||
|
* changes the full URI for the library, useful from a library table editor.
|
||||||
|
*/
|
||||||
|
void SetFullURI( const std::string& aFullURI )
|
||||||
|
{
|
||||||
|
uri = aFullURI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetOptions
|
||||||
|
* changes the options string for this record, and is useful from
|
||||||
|
* the library table editor.
|
||||||
|
*/
|
||||||
|
void SetOptions( const std::string& aOptions )
|
||||||
|
{
|
||||||
|
options = aOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FP_LIB_TABLE* owner;
|
||||||
|
std::string logicalName;
|
||||||
|
std::string type;
|
||||||
|
std::string uri;
|
||||||
|
std::string options;
|
||||||
|
|
||||||
|
PLUGIN* lib; ///< ownership of the loaded LIB is here
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor FP_LIB_TABLE
|
||||||
|
* builds a library table by pre-pending this table fragment in front of
|
||||||
|
* @a aFallBackTable. Loading of this table fragment is done by using Parse().
|
||||||
|
*
|
||||||
|
* @param aFallBackTable is another FP_LIB_TABLE which is searched only when
|
||||||
|
* a record is not found in this table. No ownership is
|
||||||
|
* taken of aFallBackTable.
|
||||||
|
*/
|
||||||
|
FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable = NULL );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Parse
|
||||||
|
* fills this table fragment from information in the input stream \a aParser, which
|
||||||
|
* is a DSNLEXER customized for the grammar needed to describe instances of this object.
|
||||||
|
* The entire textual element spec is <br>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* (fp_lib_table
|
||||||
|
* (lib (name LOGICAL)(type TYPE)(uri FULL_URI)(options OPTIONS))
|
||||||
|
* (lib (name LOGICAL)(type TYPE)(uri FULL_URI)(options OPTIONS))
|
||||||
|
* (lib (name LOGICAL)(type TYPE)(uri FULL_URI)(options OPTIONS))
|
||||||
|
* )
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* When this function is called, the input token stream given by \a aParser
|
||||||
|
* is assumed to be positioned at the '^' in the following example, i.e. just
|
||||||
|
* after the identifying keyword and before the content specifying stuff.
|
||||||
|
* <br>
|
||||||
|
* (lib_table ^ (....) )
|
||||||
|
*
|
||||||
|
* @param aParser is the input token stream of keywords and symbols.
|
||||||
|
*/
|
||||||
|
void Parse( FP_LIB_TABLE_LEXER* aParser ) throw( IO_ERROR, PARSE_ERROR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Format
|
||||||
|
* serializes this object as utf8 text to an #OUTPUTFORMATTER, and tries to
|
||||||
|
* make it look good using multiple lines and indentation.
|
||||||
|
*
|
||||||
|
* @param out is an #OUTPUTFORMATTER
|
||||||
|
* @param nestLevel is the indentation level to base all lines of the output.
|
||||||
|
* Actual indentation will be 2 spaces for each nestLevel.
|
||||||
|
*/
|
||||||
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function LookupPart
|
||||||
|
* finds and loads a MODULE, and parses it. As long as the part is
|
||||||
|
* accessible in any LIB_SOURCE, opened or not opened, this function
|
||||||
|
* will find it and load it into its containing LIB, even if that means
|
||||||
|
* having to open a LIB in this table that was not previously opened.
|
||||||
|
*
|
||||||
|
* @param aFootprintId The fully qualified name of the footprint to look up.
|
||||||
|
*
|
||||||
|
* @return MODULE* - this will never be NULL, and no ownership is transferred because
|
||||||
|
* all MODULEs live in LIBs. You only get to point to them in some LIB. If the MODULE
|
||||||
|
* cannot be found, then an exception is thrown.
|
||||||
|
*
|
||||||
|
* @throw IO_ERROR if any problem occurs or if the footprint cannot be found.
|
||||||
|
*/
|
||||||
|
MODULE* LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetLogicalLibs
|
||||||
|
* returns the logical library names, all of them that are pertinent to
|
||||||
|
* a lookup done on this FP_LIB_TABLE.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> GetLogicalLibs();
|
||||||
|
|
||||||
|
//----<read accessors>----------------------------------------------------
|
||||||
|
// the returning of a const std::string* tells if not found, but might be too
|
||||||
|
// promiscuous?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetURI
|
||||||
|
* returns the full library path from a logical library name.
|
||||||
|
* @param aLogicalLibraryName is the short name for the library of interest.
|
||||||
|
* @return const std::string* - or NULL if not found.
|
||||||
|
*/
|
||||||
|
const std::string* GetURI( const std::string& aLogicalLibraryName ) const
|
||||||
|
{
|
||||||
|
const ROW* row = FindRow( aLogicalLibraryName );
|
||||||
|
return row ? &row->uri : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetType
|
||||||
|
* returns the type of a logical library.
|
||||||
|
* @param aLogicalLibraryName is the short name for the library of interest.
|
||||||
|
* @return const std::string* - or NULL if not found.
|
||||||
|
*/
|
||||||
|
const std::string* GetType( const std::string& aLogicalLibraryName ) const
|
||||||
|
{
|
||||||
|
const ROW* row = FindRow( aLogicalLibraryName );
|
||||||
|
return row ? &row->type : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetLibOptions
|
||||||
|
* returns the options string for \a aLogicalLibraryName.
|
||||||
|
* @param aLogicalLibraryName is the short name for the library of interest.
|
||||||
|
* @return const std::string* - or NULL if not found.
|
||||||
|
*/
|
||||||
|
const std::string* GetLibOptions( const std::string& aLogicalLibraryName ) const
|
||||||
|
{
|
||||||
|
const ROW* row = FindRow( aLogicalLibraryName );
|
||||||
|
return row ? &row->options : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----</read accessors>---------------------------------------------------
|
||||||
|
|
||||||
|
#if 1 || defined(DEBUG)
|
||||||
|
/// implement the tests in here so we can honor the privilege levels of the
|
||||||
|
/// accessors, something difficult to do from int main(int, char**)
|
||||||
|
void Test();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected: // only a table editor can use these
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function InsertRow
|
||||||
|
* adds aRow if it does not already exist or if doReplace is true. If doReplace
|
||||||
|
* is not true and the key for aRow already exists, the function fails and returns false.
|
||||||
|
* The key for the table is the logicalName, and all in this table must be unique.
|
||||||
|
* @param aRow is the new row to insert, or to forcibly add if doReplace is true.
|
||||||
|
* @param doReplace if true, means insert regardless of whether aRow's key already
|
||||||
|
* exists. If false, then fail if the key already exists.
|
||||||
|
* @return bool - true if the operation succeeded.
|
||||||
|
*/
|
||||||
|
bool InsertRow( std::auto_ptr<ROW>& aRow, bool doReplace = false );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function FindRow
|
||||||
|
* returns a #ROW* if aLogicalName is found in this table or in any chained
|
||||||
|
* fallBack table fragment, else NULL.
|
||||||
|
*/
|
||||||
|
ROW* FindRow( const std::string& aLogicalName ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function lookupLib
|
||||||
|
* finds or loads a LIB based on @a aLogicalPartID or @a aFallBackLib.
|
||||||
|
* If the LIB is already loaded then it is returned as is, else it is loaded.
|
||||||
|
*
|
||||||
|
* @param aLogicalPartID holds the partName and may also hold the logicalLibName. If
|
||||||
|
* logicalLibName is empty, then @a aFallBackLib should not be NULL.
|
||||||
|
*
|
||||||
|
* @param aFallBackLib is used only if aLogicalPartID has an empty logicalLibName.
|
||||||
|
* This is for the case when an LPID has no logicalLibName because the LPID is using
|
||||||
|
* a partName from the same LIB as was the referring content.
|
||||||
|
*
|
||||||
|
* @return PLUGIN* - this will never be NULL, and no ownership is transfered because
|
||||||
|
* all LIBs live in the FP_LIB_TABLEs. You only get to point to them in some FP_LIB_TABLE.
|
||||||
|
* If the LIB cannot be found, then an exception is thrown.
|
||||||
|
*
|
||||||
|
* @throw IO_ERROR if any problem occurs or if the LIB cannot be found or cannot be loaded.
|
||||||
|
*/
|
||||||
|
PLUGIN* lookupLib( const FP_LIB_ID& aLogicalPartID ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function loadLib
|
||||||
|
* loads a LIB using information in @a aRow. Call only if LIB not
|
||||||
|
* already loaded.
|
||||||
|
*/
|
||||||
|
void loadLib( ROW* aRow ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
typedef boost::ptr_map<std::string, ROW> ROWS;
|
||||||
|
typedef ROWS::iterator ROWS_ITER;
|
||||||
|
typedef ROWS::const_iterator ROWS_CITER;
|
||||||
|
|
||||||
|
ROWS rows;
|
||||||
|
FP_LIB_TABLE* fallBack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _FP_LIB_TABLE_H_
|
|
@ -34,7 +34,7 @@
|
||||||
#include <wx/hashmap.h>
|
#include <wx/hashmap.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace PCB;
|
using namespace PCB_FILE_T;
|
||||||
|
|
||||||
|
|
||||||
class BOARD;
|
class BOARD;
|
||||||
|
|
Loading…
Reference in New Issue