see CHANGELOG.txt

This commit is contained in:
Dick Hollenbeck 2010-12-30 16:15:53 -06:00
parent 7bcb4ff34e
commit d2cc77ac71
21 changed files with 458 additions and 313 deletions

View File

@ -5,9 +5,6 @@ eeschema/cmp_library_lexer.h
eeschema/cmp_library_keywords.* eeschema/cmp_library_keywords.*
eeschema/template_fieldnames_keywords.* eeschema/template_fieldnames_keywords.*
eeschema/template_fieldnames_lexer.h eeschema/template_fieldnames_lexer.h
new/html
new/sch_lib_table_keywords.cpp
new/sch_lib_table_lexer.h
pcbnew/dialogs/dialog_freeroute_exchange_help_html.h pcbnew/dialogs/dialog_freeroute_exchange_help_html.h
Makefile Makefile
CMakeFiles CMakeFiles
@ -20,3 +17,8 @@ install_manifest.txt
Documentation/doxygen Documentation/doxygen
*.cmake *.cmake
*.bak *.bak
new/html
new/sch_lib_table_keywords.cpp
new/sch_lib_table_lexer.h
new/sweet_keywords.cpp
new/sweet_lexer.h

View File

@ -4,6 +4,19 @@ KiCad ChangeLog 2010
Please add newer entries at the top, list the date and your name with Please add newer entries at the top, list the date and your name with
email address. email address.
2010-Dec-28 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
++richio:
* Deleted kicad_exceptions, because it required the big #include <wx/wx.h> and
that was slowing down compiling. Moved that stuff back into richio.h where
it came from.
* Enhanced IO_ERROR to format an errorText.
* Added THROW_IO_ERROR() and THROW_PARSE_ERROR() macros to capture the
the call site of the thrower. If you have problems compiling, it is probably
due to the definition of __LOC__ in richio.h. Some compilers may not support
__func__ in C++ yet. Find a macro that identifies your compiler, and we can
work out something in the #define of __LOC__.
2010-Dec-28 UPDATE Dick Hollenbeck <dick@softplc.com> 2010-Dec-28 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================ ================================================================================
++new: ++new:

View File

@ -251,12 +251,14 @@ bool DSNLEXER::IsSymbol( int aTok )
void DSNLEXER::ThrowIOError( wxString aText, int charOffset ) throw( IO_ERROR ) void DSNLEXER::ThrowIOError( wxString aText, int charOffset ) throw( IO_ERROR )
{ {
// @todo convert this to THROW_PARSE_ERROR()
// append to aText, do not overwrite // append to aText, do not overwrite
aText << wxT(" ") << _("in") << wxT(" \"") << CurSource() aText << wxT(" ") << _("in") << wxT(" \"") << CurSource()
<< wxT("\" ") << _("on line") << wxT(" ") << reader->LineNumber() << wxT("\" ") << _("on line") << wxT(" ") << reader->LineNumber()
<< wxT(" ") << _("at offset") << wxT(" ") << charOffset; << wxT(" ") << _("at offset") << wxT(" ") << charOffset;
throw IO_ERROR( aText ); THROW_IO_ERROR( aText );
} }

View File

@ -113,7 +113,7 @@ unsigned FILE_LINE_READER::ReadLine() throw( IO_ERROR )
length += strlen( line + length ); length += strlen( line + length );
if( length == maxLineLength ) if( length == maxLineLength )
throw IO_ERROR( _("Line length exceeded") ); THROW_IO_ERROR( _("Line length exceeded") );
// a normal line breaks here, once through while loop // a normal line breaks here, once through while loop
if( length+1 < capacity || line[length-1] == '\n' ) if( length+1 < capacity || line[length-1] == '\n' )
@ -164,7 +164,7 @@ unsigned STRING_LINE_READER::ReadLine() throw( IO_ERROR )
if( length ) if( length )
{ {
if( length >= maxLineLength ) if( length >= maxLineLength )
throw IO_ERROR( _("Line length exceeded") ); THROW_IO_ERROR( _("Line length exceeded") );
if( length+1 > capacity ) // +1 for terminating nul if( length+1 > capacity ) // +1 for terminating nul
expandCapacity( length+1 ); expandCapacity( length+1 );
@ -305,7 +305,7 @@ std::string OUTPUTFORMATTER::Quoted( const std::string& aWrapee ) throw( IO_ERRO
// a decision was made to make all S-expression strings be on a single // a decision was made to make all S-expression strings be on a single
// line. You can embed \n (human readable) in the text but not // line. You can embed \n (human readable) in the text but not
// '\n' which is 0x0a. // '\n' which is 0x0a.
throw IO_ERROR( _( "S-expression string has newline" ) ); THROW_IO_ERROR( _( "S-expression string has newline" ) );
} }
} }
@ -363,7 +363,7 @@ void STREAM_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount ) throw( IO_
if( !os.IsOk() ) if( !os.IsOk() )
{ {
throw IO_ERROR( _( "OUTPUTSTREAM_OUTPUTFORMATTER write error" ) ); THROW_IO_ERROR( _( "OUTPUTSTREAM_OUTPUTFORMATTER write error" ) );
} }
} }
} }

View File

@ -17,25 +17,6 @@ class LIB_PIN;
class LIB_COMPONENT; class LIB_COMPONENT;
/**
* Holder of an error message and may be thrown from functions.
*/
struct Error
{
wxString errorText;
Error( const wxChar* aMsg ) :
errorText( aMsg )
{
}
Error( const wxString& aMsg ) :
errorText( aMsg )
{
}
};
/// A container for several SCH_FIELD items /// A container for several SCH_FIELD items
typedef std::vector<SCH_FIELD> SCH_FIELDS; typedef std::vector<SCH_FIELD> SCH_FIELDS;

View File

@ -1,92 +0,0 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2010 SoftPLC Corporation, <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 KICAD_EXCEPTIONS_H_
#define KICAD_EXCEPTIONS_H_
/**
* @ingroup exception_types
* @{
*/
#include <wx/string.h>
#include <string>
/**
* Struct IO_ERROR
* is a class used to hold an error message and may be used to throw exceptions
* containing meaningful error messages.
* @author Dick Hollenbeck
*/
struct IO_ERROR
{
wxString errorText;
/**
* Constructor ( const wxChar* )
* handles the case where _() is passed as aMsg.
*/
IO_ERROR( const wxChar* aMsg ) :
errorText( aMsg )
{
}
IO_ERROR( const wxString& aMsg ) :
errorText( aMsg )
{
}
IO_ERROR( const std::string& aMsg ) :
errorText( wxConvertMB2WX( aMsg.c_str() ) )
{
}
};
/**
* Class PARSE_ERROR
* contains a filename or source description, a line number, a character offset,
* and an error message.
* @author Dick Hollenbeck
*/
struct PARSE_ERROR : public IO_ERROR
{
wxString source; ///< filename typically, or other source
int lineNumber;
int byteIndex; ///< char offset, starting from 1, into the problem line.
PARSE_ERROR( const wxString& aMsg, const wxString& aSource,
int aLineNumber, int aByteIndex ) :
IO_ERROR( aMsg ),
source( aSource ),
lineNumber( aLineNumber )
{
}
};
/** @} exception_types */
#endif // KICAD_EXCEPTIONS_H_

View File

@ -38,7 +38,134 @@
// but the errorText needs to be wide char so wxString rules. // but the errorText needs to be wide char so wxString rules.
#include <wx/wx.h> #include <wx/wx.h>
#include <cstdio> #include <cstdio>
#include <kicad_exceptions.h>
/**
* @ingroup exception_types
* @{
*/
#define IO_FORMAT _( "IO_ERROR: '%s'\n from %s : %s" )
#define PARSE_FORMAT _( "PARSE_ERROR: '%s' in input/source '%s', line %d, offset %d\n from %s : %s" )
// references:
// http://stackoverflow.com/questions/2670816/how-can-i-use-the-compile-time-constant-line-in-a-string
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
// use one of the following __LOC__ defs, depending on whether your
// compiler supports __func__ or not, and how it handles __LINE__
#define __LOC__ ((std::string(__func__) + " : ") + TOSTRING(__LINE__)).c_str()
//#define __LOC__ TOSTRING(__LINE__)
/// macro which captures the "call site" values of __FILE_ & __LOC__
#define THROW_IO_ERROR( msg ) throw IO_ERROR( __FILE__, __LOC__, msg )
/**
* Struct IO_ERROR
* is a class used to hold an error message and may be used to throw exceptions
* containing meaningful error messages.
* @author Dick Hollenbeck
*/
struct IO_ERROR // : std::exception
{
wxString errorText;
/**
* Constructor
*
* @param aThrowersFile is the __FILE__ preprocessor macro but generated
* at the source file of thrower.
*
* @param aThrowersLoc can be either a function name, such as __func__
* or a stringified __LINE__ preprocessor macro but generated
* at the source function of the thrower, or concatonation. Use macro
* THROW_IO_ERROR() to wrap a call to this constructor at the call site.
*
* @param aMsg is error text that will be streamed through wxString.Printf()
* using the format string IO_FORMAT above.
*/
IO_ERROR( const char* aThrowersFile,
const char* aThrowersLoc,
const wxString& aMsg )
{
init( aThrowersFile, aThrowersLoc, aMsg );
}
IO_ERROR( const char* aThrowersFile,
const char* aThrowersLoc,
const std::string& aMsg )
{
init( aThrowersFile, aThrowersLoc, wxString::FromUTF8( aMsg.c_str() ) );
}
/**
* handles the case where _() is passed as aMsg.
*/
IO_ERROR( const char* aThrowersFile,
const char* aThrowersLoc,
const wxChar* aMsg )
{
init( aThrowersFile, aThrowersLoc, wxString( aMsg ) );
}
void init( const char* aThrowersFile, const char* aThrowersLoc, const wxString& aMsg )
{
errorText.Printf( IO_FORMAT, aMsg.GetData(),
wxString::FromUTF8( aThrowersFile ).GetData(),
wxString::FromUTF8( aThrowersLoc ).GetData() );
}
IO_ERROR() {}
~IO_ERROR() throw ( /*none*/ ){}
};
#define THROW_PARSE_ERROR( msg, input, line, offset ) throw PARSE_ERROR( __FILE__, __LOC__, msg, input, line, offset )
/**
* Class PARSE_ERROR
* contains a filename or source description, a line number, a character offset,
* and an error message.
* @author Dick Hollenbeck
*/
struct PARSE_ERROR : public IO_ERROR
{
// wxString errorText is still public from IO_ERROR
int lineNumber; ///< at which line number, 1 based index.
int byteIndex; ///< at which character position within the line, 1 based index
PARSE_ERROR( const char* aThrowersFile, const char* aThrowersLoc,
const wxString& aMsg, const wxString& aSource,
int aLineNumber, int aByteIndex ) :
IO_ERROR()
{
init( aThrowersFile, aThrowersLoc, aMsg, aSource, aLineNumber, aByteIndex );
}
void init( const char* aThrowersFile, const char* aThrowersLoc,
const wxString& aMsg, const wxString& aSource,
int aLineNumber, int aByteIndex )
{
// save line and offset in binary for Sweet text editor, which will catch exceptions
lineNumber = aLineNumber;
byteIndex = aByteIndex;
// #define PARSE_FORMAT _( "PARSE_ERROR: %s in source %s, line %d, offset %d\nfrom cpp:%s func:%s" )
errorText.Printf( PARSE_FORMAT, aMsg.GetData(), aSource.GetData(),
aLineNumber, aByteIndex,
wxString::FromUTF8( aThrowersFile ).GetData(),
wxString::FromUTF8( aThrowersLoc ).GetData() );
}
~PARSE_ERROR() throw ( /*none*/ ){}
};
/** @} exception_types */
#define LINE_READER_LINE_DEFAULT_MAX 100000 #define LINE_READER_LINE_DEFAULT_MAX 100000

View File

@ -86,6 +86,8 @@ add_executable( test_sch_lib_table
sch_lib.cpp sch_lib.cpp
sch_lpid.cpp sch_lpid.cpp
sch_dir_lib_source.cpp sch_dir_lib_source.cpp
sch_part.cpp
sweet_keywords.cpp
${PROJECT_SOURCE_DIR}/common/richio.cpp ${PROJECT_SOURCE_DIR}/common/richio.cpp
${PROJECT_SOURCE_DIR}/common/dsnlexer.cpp ${PROJECT_SOURCE_DIR}/common/dsnlexer.cpp
) )
@ -98,3 +100,10 @@ make_lexer(
${CMAKE_CURRENT_SOURCE_DIR}/sch_lib_table_keywords.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sch_lib_table_keywords.cpp
ELT_T ELT_T
) )
make_lexer(
${CMAKE_CURRENT_SOURCE_DIR}/sweet.keywords
${CMAKE_CURRENT_SOURCE_DIR}/sweet_lexer.h
${CMAKE_CURRENT_SOURCE_DIR}/sweet_keywords.cpp
PART_T
)

View File

@ -41,16 +41,10 @@
*/ */
#include <sch_dir_lib_source.h>
using namespace SCH;
#include <kicad_exceptions.h>
#include <dirent.h> #include <dirent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@ -61,11 +55,8 @@ using namespace SCH;
#include <vector> #include <vector>
using namespace std; using namespace std;
/// This file extension is an implementation detail specific to this LIB_SOURCE #include <sch_dir_lib_source.h>
/// implementation, and to a corresponding LIB_SINK. using namespace SCH;
/// Core EESCHEMA should never have to see this.
#define SWEET_EXT ".part"
#define SWEET_EXTZ (sizeof(SWEET_EXT)-1)
/* __func__ is C99 prescribed, but just in case: /* __func__ is C99 prescribed, but just in case:
@ -157,7 +148,7 @@ static inline bool isDigit( char c )
* segment, i.e. the string segment of interest is [start,tail) * segment, i.e. the string segment of interest is [start,tail)
* @param separator is the separating byte, expected: '.' or '/', depending on context. * @param separator is the separating byte, expected: '.' or '/', depending on context.
*/ */
static const char* endsWithRev( const char* start, const char* tail, char separator ) static const char* endsWithRev( const char* start, const char* tail, char separator = '/' )
{ {
bool sawDigit = false; bool sawDigit = false;
@ -181,7 +172,7 @@ static const char* endsWithRev( const char* start, const char* tail, char separa
return 0; return 0;
} }
static inline const char* endsWithRev( const STRING& aPartName, char separator ) static inline const char* endsWithRev( const STRING& aPartName, char separator = '/' )
{ {
return endsWithRev( aPartName.c_str(), aPartName.c_str()+aPartName.size(), separator ); return endsWithRev( aPartName.c_str(), aPartName.c_str()+aPartName.size(), separator );
} }
@ -194,8 +185,8 @@ bool BY_REV::operator() ( const STRING& s1, const STRING& s2 ) const
{ {
// avoid instantiating new STRINGs, and thank goodness that c_str() is const. // avoid instantiating new STRINGs, and thank goodness that c_str() is const.
const char* rev1 = endsWithRev( s1, '/' ); const char* rev1 = endsWithRev( s1 );
const char* rev2 = endsWithRev( s2, '/' ); const char* rev2 = endsWithRev( s2 );
int rootLen1 = rev1 ? rev1 - s1.c_str() : s1.size(); int rootLen1 = rev1 ? rev1 - s1.c_str() : s1.size();
int rootLen2 = rev2 ? rev2 - s2.c_str() : s2.size(); int rootLen2 = rev2 ? rev2 - s2.c_str() : s2.size();
@ -290,7 +281,7 @@ STRING DIR_LIB_SOURCE::makeFileName( const STRING& aPartName )
STRING fileName = sourceURI + "/"; STRING fileName = sourceURI + "/";
const char* rev = endsWithRev( aPartName, '/' ); const char* rev = endsWithRev( aPartName );
if( rev ) if( rev )
{ {
@ -318,7 +309,7 @@ void DIR_LIB_SOURCE::readString( STRING* aResult, const STRING& aFileName ) thro
{ {
STRING msg = strerror( errno ); STRING msg = strerror( errno );
msg += "; cannot open(O_RDONLY) file " + aFileName; msg += "; cannot open(O_RDONLY) file " + aFileName;
throw( IO_ERROR( msg ) ); THROW_IO_ERROR( msg );
} }
struct stat fs; struct stat fs;
@ -330,9 +321,14 @@ void DIR_LIB_SOURCE::readString( STRING* aResult, const STRING& aFileName ) thro
{ {
STRING msg = aFileName; STRING msg = aFileName;
msg += " seems too big. ( > 1 mbyte )"; msg += " seems too big. ( > 1 mbyte )";
throw IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
#if 0
// I read somewhere on the Internet that std::string chars are not guaranteed
// (over time) to be contiguous in future implementations of C++, so this
// strategy is here for that eventuality. We buffer through readBuffer here.
// reuse same readBuffer, which is not thread safe, but the API // reuse same readBuffer, which is not thread safe, but the API
// is not advertising thread safe (yet, if ever). // is not advertising thread safe (yet, if ever).
if( (int) fs.st_size > (int) readBuffer.size() ) if( (int) fs.st_size > (int) readBuffer.size() )
@ -343,13 +339,27 @@ void DIR_LIB_SOURCE::readString( STRING* aResult, const STRING& aFileName ) thro
{ {
STRING msg = strerror( errno ); STRING msg = strerror( errno );
msg += "; cannot read file " + aFileName; msg += "; cannot read file " + aFileName;
throw( IO_ERROR( msg ) ); THROW_IO_ERROR( msg );
} }
// std::string chars are not guaranteed to be contiguous in
// future implementations of C++, so this is why we did not read into
// aResult directly.
aResult->assign( &readBuffer[0], count ); aResult->assign( &readBuffer[0], count );
#else
// read into the string directly
aResult->resize( fs.st_size );
int count = read( fw, &(*aResult)[0], fs.st_size );
if( count != (int) fs.st_size )
{
STRING msg = strerror( errno );
msg += "; cannot read file " + aFileName;
THROW_IO_ERROR( msg );
}
// test trailing nul is there, which should have been put there with resize() above
// printf( "'%s'\n", aResult->c_str() ); // checked OK.
#endif
} }
@ -371,7 +381,7 @@ DIR_LIB_SOURCE::DIR_LIB_SOURCE( const STRING& aDirectoryPath,
if( sourceURI.size() == 0 ) if( sourceURI.size() == 0 )
{ {
throw( IO_ERROR( STRING("aDirectoryPath cannot be empty") ) ); THROW_IO_ERROR( STRING("aDirectoryPath cannot be empty") );
} }
// remove any trailing separator, so we can add it back later without ambiguity // remove any trailing separator, so we can add it back later without ambiguity
@ -406,7 +416,7 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a
while( it != limit ) while( it != limit )
{ {
const char* rev = endsWithRev( *it, '/' ); const char* rev = endsWithRev( *it );
// all cached partnames have a rev string in useVersioning mode // all cached partnames have a rev string in useVersioning mode
assert( rev ); assert( rev );
@ -434,7 +444,13 @@ void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const S
throw( IO_ERROR ) throw( IO_ERROR )
{ {
STRING partName = aPartName; // appended with aRev too if not empty STRING partName = aPartName; // appended with aRev too if not empty
const char* rev = endsWithRev( partName, '/' ); const char* rev = endsWithRev( partName );
if( !useVersioning && (aRev.size() || rev) )
{
STRING msg = "this type 'dir' LIB_SOURCE not using 'useVersioning' option, cannot ask for a revision";
THROW_IO_ERROR( msg );
}
if( aRev.size() ) if( aRev.size() )
{ {
@ -443,7 +459,7 @@ void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const S
partName += "/" + aRev; partName += "/" + aRev;
rev = endsWithRev( partName, '/' ); rev = endsWithRev( partName );
} }
// partName is the exact part name we need here, or if rev is NULL, // partName is the exact part name we need here, or if rev is NULL,
@ -456,7 +472,7 @@ void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const S
if( it == partnames.end() ) // part not found if( it == partnames.end() ) // part not found
{ {
partName += " not found."; partName += " not found.";
throw IO_ERROR( partName ); THROW_IO_ERROR( partName );
} }
readString( aResult, makeFileName( partName ) ); readString( aResult, makeFileName( partName ) );
@ -474,8 +490,9 @@ void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const S
// some unrelated name that is larger. // some unrelated name that is larger.
if( it == partnames.end() || it->compare( 0, search.size(), search ) != 0 ) if( it == partnames.end() || it->compare( 0, search.size(), search ) != 0 )
{ {
partName += " rev not found."; partName.insert( partName.begin(), '\'' );
throw IO_ERROR( partName ); partName += "' is not present without a revision.";
THROW_IO_ERROR( partName );
} }
readString( aResult, makeFileName( *it ) ); readString( aResult, makeFileName( *it ) );
@ -540,7 +557,7 @@ void DIR_LIB_SOURCE::cacheOneDir( const STRING& aCategory ) throw( IO_ERROR )
{ {
STRING msg = strerror( errno ); STRING msg = strerror( errno );
msg += "; scanning directory " + curDir; msg += "; scanning directory " + curDir;
throw( IO_ERROR( msg ) ); THROW_IO_ERROR( msg );
} }
struct stat fs; struct stat fs;
@ -566,7 +583,7 @@ void DIR_LIB_SOURCE::cacheOneDir( const STRING& aCategory ) throw( IO_ERROR )
{ {
STRING msg = partName; STRING msg = partName;
msg += " has already been encountered"; msg += " has already been encountered";
throw IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
} }
@ -649,9 +666,9 @@ void DIR_LIB_SOURCE::Test( int argc, char** argv )
printf( "std::exception\n" ); printf( "std::exception\n" );
} }
catch( IO_ERROR ioe ) catch( IO_ERROR& ioe )
{ {
printf( "exception: %s\n", (const char*) wxConvertWX2MB( ioe.errorText ) ); printf( "exception: %s\n", (const char*) ioe.errorText.ToUTF8() ) );
} }
} }

View File

@ -26,11 +26,18 @@
#define DIR_LIB_SOURCE_H_ #define DIR_LIB_SOURCE_H_
#include <sch_lib.h>
#include <set> #include <set>
#include <vector> #include <vector>
#include <sch_lib.h>
/// This file extension is an implementation detail specific to this LIB_SOURCE
/// and to a corresponding LIB_SINK.
/// Core EESCHEMA should never have to see this.
#define SWEET_EXT ".part"
#define SWEET_EXTZ (sizeof(SWEET_EXT)-1)
/** /**
* struct BY_REV * struct BY_REV

View File

@ -22,9 +22,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <memory> // std::auto_ptr
#include <wx/string.h>
#include <sch_lib.h> #include <sch_lib.h>
#include <sch_lpid.h>
#include <sch_part.h>
#include <sweet_lexer.h>
#include <sch_lib_table.h>
using namespace SCH; using namespace SCH;
@ -44,9 +49,40 @@ LIB::~LIB()
} }
PART* LIB::LookupPart( const LPID& aLPID ) throw( IO_ERROR ) PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR )
{ {
return 0; PART* part;
// If part not already cached
if( 1 /* @todo test cache */ )
{
// load it.
part = new PART( this, aLPID.GetPartName(), aLPID.GetRevision() );
std::auto_ptr<PART> wrapped( part );
source->ReadPart( &part->body, aLPID.GetPartName(), aLPID.GetRevision() );
#if defined(DEBUG)
const STRING& body = part->body;
printf( "body: %s", body.c_str() );
if( !body.size() || body[body.size()-1] != '\n' )
printf( "\n" );
#endif
SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ );
part->Parse( &sw, aLibTable );
// stuff the part into this LIBs cache:
// @todo
wrapped.release();
}
return part;
} }

View File

@ -26,14 +26,14 @@
#define SCH_LIB_H_ #define SCH_LIB_H_
#include <utf8.h> #include <utf8.h>
#include <kicad_exceptions.h> #include <richio.h>
namespace SCH { namespace SCH {
class LPID; class LPID;
class PART; class PART;
class LIB_TABLE;
/** /**
* Class LIB_SOURCE * Class LIB_SOURCE
@ -69,7 +69,7 @@ protected: ///< derived classes must implement
* Function ReadPart * Function ReadPart
* fetches @a aPartName's s-expression into @a aResult after clear()ing aResult. * fetches @a aPartName's s-expression into @a aResult after clear()ing aResult.
*/ */
virtual void ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev = "" ) virtual void ReadPart( STR_UTF* aResult, const STRING& aPartName, const STRING& aRev = "" )
throw( IO_ERROR ) = 0; throw( IO_ERROR ) = 0;
/** /**
@ -80,7 +80,7 @@ protected: ///< derived classes must implement
* does not have a version string, then the most recent version is fetched. * does not have a version string, then the most recent version is fetched.
* @param aResults receives the s-expressions * @param aResults receives the s-expressions
*/ */
virtual void ReadParts( STRINGS* aResults, const STRINGS& aPartNames ) virtual void ReadParts( STR_UTFS* aResults, const STRINGS& aPartNames )
throw( IO_ERROR ) = 0; throw( IO_ERROR ) = 0;
/** /**
@ -239,12 +239,15 @@ public:
* @param aLPID is the part to lookup. The logicalLibName can be empty in it * @param aLPID is the part to lookup. The logicalLibName can be empty in it
* since yes, we know which LIB is in play. * since yes, we know which LIB is in play.
* *
* @param aLibTable is the LIB_TABLE view that is in effect for inheritance,
* and comes from the big containing SCHEMATIC object.
*
* @return PART* - The desired PART and will never be NULL. No ownership is * @return PART* - The desired PART and will never be NULL. No ownership is
* given to caller. PARTs always reside in the cache that is a LIB. * given to caller. PARTs always reside in the cache that is a LIB.
* *
* @throw IO_ERROR if the part cannot be found or loaded. * @throw IO_ERROR if the part cannot be found or loaded.
*/ */
PART* LookupPart( const LPID& aLPID ) PART* LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable )
throw( IO_ERROR ); throw( IO_ERROR );
/** /**
@ -315,13 +318,13 @@ public:
protected: protected:
STRING fetch; // scratch, used to fetch things, grows to worst case size. STR_UTF fetch; // scratch, used to fetch things, grows to worst case size.
STRINGS vfetch; // scratch, used to fetch things. STR_UTFS vfetch; // scratch, used to fetch things.
STRING name; STRING name;
LIB_SOURCE* source; LIB_SOURCE* source;
LIB_SINK* sink; LIB_SINK* sink;
STRING libraryURI; // STRING libraryURI;
STRINGS categories; STRINGS categories;

View File

@ -132,7 +132,7 @@ void LIB_TABLE::Parse( SCH_LIB_TABLE_LEXER* in ) throw( IO_ERROR )
msg += row->logicalName; msg += row->logicalName;
msg += '\''; msg += '\'';
msg += " is a duplicate logical lib name"; msg += " is a duplicate logical lib name";
throw IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
} }
} }
@ -187,53 +187,46 @@ STRINGS LIB_TABLE::GetLogicalLibs()
} }
PART* LIB_TABLE::LookupPart( const LPID& aLogicalPartID, LIB* aLocalLib ) PART* LIB_TABLE::LookupPart( const LPID& aLPID, LIB* aLocalLib )
throw( IO_ERROR ) throw( IO_ERROR )
{ {
LIB* lib = lookupLib( aLogicalPartID, aLocalLib ); LIB* lib = lookupLib( aLPID, aLocalLib );
return lib->LookupPart( aLogicalPartID ); return lib->LookupPart( aLPID, this );
} }
LIB* LIB_TABLE::lookupLib( const LPID& aLogicalPartID, LIB* aLocalLib ) LIB* LIB_TABLE::lookupLib( const LPID& aLPID, LIB* aFallBackLib )
throw( IO_ERROR ) throw( IO_ERROR )
{ {
if( aLocalLib ) if( aLPID.GetLogicalLib().size() )
{ {
return aLocalLib; ROW* row = FindRow( aLPID.GetLogicalLib() );
} if( !row )
else
{
const STRING& logName = aLogicalPartID.GetLogicalLib();
if( logName.size() )
{ {
ROW* row = FindRow( logName ); STRING msg = "lib table contains no logical lib '";
if( !row ) msg += aLPID.GetLogicalLib();
{ msg += '\'';
STRING msg = "Unable to find logical lib "; THROW_IO_ERROR( msg );
msg += logName;
throw IO_ERROR( msg );
}
if( !row->lib )
{
loadLib( row );
}
assert( row->lib ); // loadLib() throws if cannot load
return row->lib;
} }
else
if( !row->lib )
{ {
STRING msg = "No logicalLibName in LPID and no localLib"; loadLib( row );
throw IO_ERROR( msg );
} }
assert( row->lib ); // fix loadLib() to throw if cannot load
return row->lib;
} }
// return NULL; never get here if( aFallBackLib )
{
return aFallBackLib;
}
STRING msg = "lookupLib() requires logicalLibName or a fallback lib";
THROW_IO_ERROR( msg );
} }
@ -262,6 +255,7 @@ void LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR )
aRow->lib = new LIB( aRow->GetLogicalName(), source.release(), NULL ); aRow->lib = new LIB( aRow->GetLogicalName(), source.release(), NULL );
} }
/*
else if( !libType.compare( "schematic" ) ) else if( !libType.compare( "schematic" ) )
{ {
// @todo code and load SCHEMATIC_LIB_SOURCE // @todo code and load SCHEMATIC_LIB_SOURCE
@ -276,6 +270,14 @@ void LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR )
{ {
// @todo code and load HTTP_LIB_SOURCE // @todo code and load HTTP_LIB_SOURCE
} }
*/
else
{
STRING msg = "cannot load unknown libType: '";
msg += libType;
msg += '\'';
THROW_IO_ERROR( msg );
}
} }
@ -334,44 +336,34 @@ bool LIB_TABLE::InsertRow( std::auto_ptr<ROW>& aRow, bool doReplace )
} }
#if 0 && defined(DEBUG) #if 1 && defined(DEBUG)
// build this with a Debug CMAKE_BUILD_TYPE // build this with a Debug CMAKE_BUILD_TYPE
void LIB_TABLE::Test() void LIB_TABLE::Test()
{ {
// the null string is not really a legal DSN token since any duplicated // A pair of double quotes alone, is not really a legal DSN token since
// double quote ("") is assumed to be a single double quote ("). // any duplicated double quote ("") is assumed to be a single double quote (")
// To pass an empty string, we can pass " " to (options " ") // in any DSN lexer.
// To pass an empty string, we can pass " " to (options " "), or if you passed
// """" this would show up as "" with quotes present in the parser. The parser
// probably doesn't want a pair of double quotes, strlen() = 2.
SCH_LIB_TABLE_LEXER slr( SCH_LIB_TABLE_LEXER slr(
"(lib_table \n" "(lib_table \n"
" (lib (logical www) (type http) (full_uri http://kicad.org/libs) (options \" \"))\n" " (lib (logical www) (type http) (full_uri http://kicad.org/libs) (options \" \"))\n"
" (lib (logical meparts) (type dir) (full_uri /tmp/eeschema-lib) (options \" \"))\n" " (lib (logical meparts) (type dir) (full_uri /tmp/eeschema-lib) (options useVersioning))\n"
" (lib (logical old-project) (type schematic)(full_uri /tmp/old-schematic.sch) (options \" \"))\n" " (lib (logical old-project) (type schematic)(full_uri /tmp/old-schematic.sch) (options \" \"))\n"
, ,
wxT( "inline text" ) // source wxT( "inline text" ) // source
); );
try // read the "( lib_table" pair of tokens
{ slr.NextTok();
// read the "( lib_table" pair of tokens slr.NextTok();
slr.NextTok();
slr.NextTok();
// parse the rest of input to slr // parse the rest of input to slr
Parse( &slr ); Parse( &slr );
}
catch( std::exception& ex )
{
printf( "std::exception\n" );
}
catch( IO_ERROR ioe )
{
printf( "exception: %s\n", (const char*) wxConvertWX2MB( ioe.errorText ) );
}
STRING_FORMATTER sf; STRING_FORMATTER sf;
@ -401,6 +393,11 @@ void LIB_TABLE::Test()
{ {
printf( "logicalName: %s\n", it->c_str() ); printf( "logicalName: %s\n", it->c_str() );
} }
// find a part
LPID lpid( "meparts:tigers/ears/rev10" );
LookupPart( lpid );
} }
@ -408,7 +405,18 @@ int main( int argc, char** argv )
{ {
LIB_TABLE lib_table; LIB_TABLE lib_table;
lib_table.Test(); try
{
// test exceptions:
// THROW_PARSE_ERROR( wxT("test problem"), wxT("input"), 23, 46 );
//THROW_IO_ERROR( wxT("io test") );
lib_table.Test();
}
catch( IO_ERROR& ioe )
{
printf( "%s\n", (const char*) ioe.errorText.ToUTF8() );
}
return 0; return 0;
} }

View File

@ -350,14 +350,12 @@ private:
* finds or loads a LIB based on @a aLogicalPartID or @a aFallBackLib. * 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. * If the LIB is already loaded then it is returned as is, else it is loaded.
* *
* @param aLogicalPartID may hold the logicalLibName. If * @param aLogicalPartID holds the partName and may also hold the logicalLibName. If
* logicalLibName is empty, then @a aLocalLib should not be NULL. * logicalLibName is empty, then @a aFallBackLib should not be NULL.
* *
* @param aLocalLib is used if not NULL, and should be supplied especiallly if * @param aFallBackLib is used only if aLogicalPartID has an empty logicalLibName.
* aLogicalPartID has an empty logicalLibName. This is for the case when * This is for the case when an LPID has no logicalLibName because the LPID is using
* a partName must come from the same LIB as the referring content. * a partName from the same LIB as was the referring content.
* For example, a PART extends another PART in the same LIB and the extends
* LPID has no logical lib name.
* *
* @return LIB* - this will never be NULL, and no ownership is transfered because * @return LIB* - this will never be NULL, and no ownership is transfered because
* all LIBs live in the LIB_TABLEs. You only get to point to them in some LIB_TABLE. * all LIBs live in the LIB_TABLEs. You only get to point to them in some LIB_TABLE.
@ -365,7 +363,7 @@ private:
* *
* @throw IO_ERROR if any problem occurs or if the LIB cannot be found or cannot be loaded. * @throw IO_ERROR if any problem occurs or if the LIB cannot be found or cannot be loaded.
*/ */
LIB* lookupLib( const LPID& aLogicalPartID, LIB* aLocalLib = NULL ) throw( IO_ERROR ); LIB* lookupLib( const LPID& aLogicalPartID, LIB* aFallBackLib = NULL ) throw( IO_ERROR );
/** /**
* Function loadLib * Function loadLib

View File

@ -114,6 +114,7 @@ int LPID::Parse( const STRING& aLPID )
logical.clear(); logical.clear();
category.clear(); category.clear();
baseName.clear(); baseName.clear();
partName.clear();
revision.clear(); revision.clear();
const char* rev = EndsWithRev( aLPID ); const char* rev = EndsWithRev( aLPID );
@ -183,7 +184,7 @@ LPID::LPID( const STRING& aLPID ) throw( PARSE_ERROR )
if( offset != -1 ) if( offset != -1 )
{ {
throw PARSE_ERROR( THROW_PARSE_ERROR(
_( "Illegal character found in LPID string" ), _( "Illegal character found in LPID string" ),
wxConvertMB2WX( aLPID.c_str() ), wxConvertMB2WX( aLPID.c_str() ),
0, 0,
@ -193,12 +194,6 @@ LPID::LPID( const STRING& aLPID ) throw( PARSE_ERROR )
} }
const STRING& LPID::GetLogicalLib() const
{
return logical;
}
int LPID::SetLogicalLib( const STRING& aLogical ) int LPID::SetLogicalLib( const STRING& aLogical )
{ {
int offset = okLogical( aLogical ); int offset = okLogical( aLogical );
@ -210,63 +205,49 @@ int LPID::SetLogicalLib( const STRING& aLogical )
} }
const STRING& LPID::GetCategory() const
{
return category;
}
int LPID::SetCategory( const STRING& aCategory ) int LPID::SetCategory( const STRING& aCategory )
{ {
int offset = okCategory( aCategory ); int offset = okCategory( aCategory );
if( offset == -1 ) if( offset == -1 )
{ {
category = aCategory; category = aCategory;
// set the partName too
if( category.size() )
{
partName = category;
partName += '/';
partName += baseName;
}
else
partName = baseName;
} }
return offset; return offset;
} }
const STRING& LPID::GetBaseName() const
{
return baseName;
}
int LPID::SetBaseName( const STRING& aBaseName ) int LPID::SetBaseName( const STRING& aBaseName )
{ {
int offset = okBase( aBaseName ); int offset = okBase( aBaseName );
if( offset == -1 ) if( offset == -1 )
{ {
baseName = aBaseName; baseName = aBaseName;
// set the partName too
if( category.size() )
{
partName = category;
partName += '/';
partName += baseName;
}
else
partName = baseName;
} }
return offset; return offset;
} }
STRING LPID::GetPartName() const
{
STRING ret;
// return [category/]baseName
if( category.size() )
{
ret += category;
ret += '/';
}
ret += baseName;
return ret;
}
const STRING& LPID::GetRevision() const
{
return revision;
}
int LPID::SetRevision( const STRING& aRevision ) int LPID::SetRevision( const STRING& aRevision )
{ {
int offset = okRevision( aRevision ); int offset = okRevision( aRevision );
@ -306,7 +287,7 @@ STRING LPID::Format() const
} }
#if 1 && defined(DEBUG) #if 0 && defined(DEBUG)
// build this with Debug CMAKE_BUILD_TYPE // build this with Debug CMAKE_BUILD_TYPE

View File

@ -26,7 +26,7 @@
#define SCH_LPID_H_ #define SCH_LPID_H_
#include <utf8.h> #include <utf8.h>
#include <kicad_exceptions.h> #include <richio.h>
namespace SCH { namespace SCH {
@ -84,7 +84,10 @@ public:
* for this portion since it comes from the library table and is considered * for this portion since it comes from the library table and is considered
* read only here. * read only here.
*/ */
const STRING& GetLogicalLib() const; const STRING& GetLogicalLib() const
{
return logical;
}
/** /**
* Function SetCategory * Function SetCategory
@ -100,7 +103,10 @@ public:
* returns the category of this part id, "passives" in the example at the * returns the category of this part id, "passives" in the example at the
* top of the class description. * top of the class description.
*/ */
const STRING& GetCategory() const; const STRING& GetCategory() const
{
return category;
}
/** /**
* Function SetCategory * Function SetCategory
@ -116,7 +122,10 @@ public:
* Function GetBaseName * Function GetBaseName
* returns the part name without the category. * returns the part name without the category.
*/ */
const STRING& GetBaseName() const; const STRING& GetBaseName() const
{
return baseName;
}
/** /**
* Function SetBaseName * Function SetBaseName
@ -131,20 +140,19 @@ public:
* Function GetPartName * Function GetPartName
* returns the part name, i.e. category/baseName without revision. * returns the part name, i.e. category/baseName without revision.
*/ */
STRING GetPartName() const; const STRING& GetPartName() const
{
/** return partName;
* Function SetBaseName }
* overrides the part name portion of the LPID to @a aPartName
not really needed, partname is an agreggate anyway, just parse a new one.
void SetPartName( const STRING& aPartName );
*/
/** /**
* Function GetRevision * Function GetRevision
* returns the revision portion of the LPID. * returns the revision portion of the LPID.
*/ */
const STRING& GetRevision() const; const STRING& GetRevision() const
{
return revision;
}
/** /**
* Function SetRevision * Function SetRevision
@ -171,6 +179,7 @@ protected:
STRING category; ///< or empty STRING category; ///< or empty
STRING baseName; ///< without category STRING baseName; ///< without category
STRING revision; ///< "revN[N..]" or empty STRING revision; ///< "revN[N..]" or empty
STRING partName; ///< cannot be set directory, set via SetBaseName() & SetCategory()
}; };
} // namespace SCH } // namespace SCH

View File

@ -22,12 +22,18 @@
*/ */
#include "sch_part.h" #include <sch_part.h>
#include <sweet_lexer.h>
#include <wx/wx.h> // _()
using namespace SCH; using namespace SCH;
void PART::Parse( LIB* aLexer ) throw( PARSE_ERROR )
void PART::Parse( SWEET_LEXER* aLexer, LIB_TABLE* aTable ) throw( PARSE_ERROR )
{ {
// Wayne's world, if he still wants it.
} }

View File

@ -27,9 +27,31 @@
#include <sch_lib.h> #include <sch_lib.h>
class SWEET_LEXER;
namespace SCH { namespace SCH {
/**
* Enum PartBit
* is a set of bit positions that can be used to create flag bits within
* PART::contains to indicate what state the PART is in and what it contains, i.e.
* whether the PART has been parsed, and what the PART contains, categorically.
*/
enum PartBit
{
PARSED, ///< have parsed this part already, otherwise 'body' text must be parsed
EXTENDS, ///< saw and "extends" keyword, inheriting from another PART
};
/// Function PB
/// is a PartBit shifter for PART::contains field.
static inline const int PB( PartBit oneBitOnly )
{
return ( 1 << oneBitOnly );
}
/** /**
* Class PART * Class PART
* will have to be unified with what Wayne is doing. I want a separate copy * will have to be unified with what Wayne is doing. I want a separate copy
@ -47,19 +69,23 @@ class PART
/// be done by PARTS_LIST, a class derived from LIB. /// be done by PARTS_LIST, a class derived from LIB.
friend class LIB; friend class LIB;
/// a private constructor, only a LIB can instantiate a PART. /// a private constructor, only a LIB can instantiate a PART.
PART() {} PART( LIB* aOwner, const STRING& aPartName, const STRING& aRevision ) :
owner( aOwner ),
contains( 0 ),
partName( aPartName ),
revision( aRevision )
{}
protected: // not likely to have C++ descendants, but protected none-the-less. protected: // not likely to have C++ descendants, but protected none-the-less.
bool parsed; ///< true if the body as been parsed already.
LIB* owner; ///< which LIB am I a part of (pun if you want) LIB* owner; ///< which LIB am I a part of (pun if you want)
int contains; ///< has bits from Enum PartParts
STRING extends; ///< LPID of base part STRING extends; ///< LPID of base part
STRING name; ///< example "passives/R", immutable. STRING partName; ///< example "passives/R", immutable.
STRING revision; // @todo need a single search key, this won't do.
/// s-expression text for the part, initially empty, and read in as this part /// s-expression text for the part, initially empty, and read in as this part
/// actually becomes cached in RAM. /// actually becomes cached in RAM.
@ -81,7 +107,6 @@ protected: // not likely to have C++ descendants, but protected none-the-le
// lots of other stuff, like the mandatory properties. // lots of other stuff, like the mandatory properties.
public: public:
/** /**
@ -91,7 +116,6 @@ public:
*/ */
void Inherit( const PART& aBasePart ); void Inherit( const PART& aBasePart );
/** /**
* Function Owner * Function Owner
* returns the LIB* owner of this part. * returns the LIB* owner of this part.
@ -100,12 +124,23 @@ public:
/** /**
* Function Parse * Function Parse
* translates the \a body string into a binary form that is represented * translates a Sweet string into a binary form that is represented
* by the normal fields of this class. Parse is expected to call Inherit() * by the normal fields of this class. Parse is expected to call Inherit()
* if this part extends any other. * if this part extends any other.
*
* @param aLexer is an instance of SWEET_LEXER, rewound at the first line.
*
* @param aLibTable is the LIB_TABLE view that is in effect for inheritance,
* and comes from the big containing SCHEMATIC object.
*/ */
void Parse( LIB* aLexer ) throw( PARSE_ERROR ); void Parse( SWEET_LEXER* aLexer, LIB_TABLE* aTable ) throw( PARSE_ERROR );
/*
void SetBody( const STR_UTF& aSExpression )
{
body = aSExpression;
}
*/
}; };
} // namespace PART } // namespace PART

2
new/sweet.keywords Normal file
View File

@ -0,0 +1,2 @@
part
extends

View File

@ -13,14 +13,19 @@
/** /**
* Type STRING * Type STRING
* holds a sequence of 8 bit bytes that represent a sequence * holds a sequence of 8 bit bytes that represent a sequence of variable
* of variable multi-byte international characters, with unspecified encoding. * length multi-byte international characters, with unspecified encoding.
*/ */
typedef std::string STRING; typedef std::string STRING;
/**
* Type STRINGS
* is an "array like" list of STRINGs
*/
typedef std::deque<STRING> STRINGS;
/** /**
* Type STRING_UTF8 * Type STR_UTF
* holds a UTF8 encoded sequence of 8 bit bytes that represent a sequence * holds a UTF8 encoded sequence of 8 bit bytes that represent a sequence
* of variable multi-byte international characters. UTF8 is the chosen encoding * of variable multi-byte international characters. UTF8 is the chosen encoding
* for all Kicad data files so that they can be transported from one nation to another * for all Kicad data files so that they can be transported from one nation to another
@ -29,19 +34,15 @@ typedef std::string STRING;
* Filenames may be encoded on disk using an encoding chosen by the host operating * Filenames may be encoded on disk using an encoding chosen by the host operating
* system. Nonetheless, Kicad data file _content_ is always UTF8 encoded, regardless * system. Nonetheless, Kicad data file _content_ is always UTF8 encoded, regardless
* of host operating system. * of host operating system.
* STRING_UTF is UTF8 encoded, by definition. * STR_UTF is UTF8 encoded, by definition.
*/ */
typedef STRING STRING_UTF8; typedef STRING STR_UTF;
/** /**
* Type STRINGS_UTF8 * Type STR_UTFS
* is an "array like" list of STRING_UTF8s * is an "array like" list of STR_UTFs
*/ */
typedef std::deque<STRING> STRINGS_UTF8; typedef std::deque<STRING> STR_UTFS;
typedef std::deque<STRING> STRINGS;
/** @} string_types */ /** @} string_types */

View File

@ -542,7 +542,7 @@ void SPECCTRA_DB::ThrowIOError( const wxChar* fmt, ... ) throw( IO_ERROR )
errText.PrintfV( fmt, args ); errText.PrintfV( fmt, args );
va_end( args ); va_end( args );
throw IO_ERROR( errText ); THROW_IO_ERROR( errText );
} }