9 changed files with 1348 additions and 6 deletions
-
2.bzrignore
-
6CMakeLists.txt
-
11common/CMakeLists.txt
-
413common/fp_lib_id.cpp
-
312common/fp_lib_table.cpp
-
9common/fp_lib_table.keywords
-
220include/fp_lib_id.h
-
379include/fp_lib_table.h
-
2pcbnew/pcb_parser.h
@ -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_ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue