More robust file reading for simulator files.
This commit is contained in:
parent
afc6b325b2
commit
c381b6d024
|
@ -106,6 +106,47 @@ std::string StrPrintf( const char* format, ... )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString SafeReadFile( const wxString& aFilePath, const wxString& aReadType )
|
||||||
|
{
|
||||||
|
auto FROM_UTF8_WINE =
|
||||||
|
[]( const char* cstring )
|
||||||
|
{
|
||||||
|
wxString line = wxString::FromUTF8( cstring );
|
||||||
|
|
||||||
|
if( line.IsEmpty() ) // happens when cstring is not a valid UTF8 sequence
|
||||||
|
line = wxConvCurrent->cMB2WC( cstring ); // try to use locale conversion
|
||||||
|
|
||||||
|
// We have trouble here *probably* because Wine-hosted LTSpice writes out MSW
|
||||||
|
// encoded text on a macOS, where it isn't expected. In any case, wxWidgets'
|
||||||
|
// wxSafeConvert() appears to get around it.
|
||||||
|
|
||||||
|
if( line.IsEmpty() )
|
||||||
|
line = wxSafeConvertMB2WX( cstring );
|
||||||
|
|
||||||
|
// I'm not sure what the source of this style of line-endings is, but it can be
|
||||||
|
// found in some Fairchild Semiconductor SPICE files.
|
||||||
|
line.Replace( wxS( "\r\r\n" ), wxS( "\n" ) );
|
||||||
|
|
||||||
|
return line;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open file
|
||||||
|
FILE* fp = wxFopen( aFilePath, aReadType );
|
||||||
|
|
||||||
|
if( !fp )
|
||||||
|
THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'." ), aFilePath ) );
|
||||||
|
|
||||||
|
FILE_LINE_READER fileReader( fp, aFilePath );
|
||||||
|
|
||||||
|
wxString contents;
|
||||||
|
|
||||||
|
while( fileReader.ReadLine() )
|
||||||
|
contents += FROM_UTF8_WINE( fileReader.Line() );
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----<LINE_READER>------------------------------------------------------
|
//-----<LINE_READER>------------------------------------------------------
|
||||||
|
|
||||||
LINE_READER::LINE_READER( unsigned aMaxLineLength ) :
|
LINE_READER::LINE_READER( unsigned aMaxLineLength ) :
|
||||||
|
|
|
@ -88,8 +88,8 @@ wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath,
|
wxString SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const wxString& aLibPath,
|
||||||
const std::string& aRelativeLib )
|
const wxString& aRelativeLib )
|
||||||
{
|
{
|
||||||
wxFileName testPath( aLibPath );
|
wxFileName testPath( aLibPath );
|
||||||
wxString fullPath( aLibPath );
|
wxString fullPath( aLibPath );
|
||||||
|
@ -123,7 +123,7 @@ std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath
|
||||||
catch( ... )
|
catch( ... )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
return fullPath.ToStdString();
|
return fullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath )
|
||||||
{
|
{
|
||||||
wxString path = ResolveLibraryPath( aLibraryPath, m_project );
|
wxString path = ResolveLibraryPath( aLibraryPath, m_project );
|
||||||
|
|
||||||
std::function<std::string(const std::string&, const std::string&)> f2 =
|
std::function<wxString(const wxString&, const wxString&)> f2 =
|
||||||
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
|
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
|
||||||
|
|
||||||
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, m_reporter, &f2 );
|
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, m_reporter, &f2 );
|
||||||
|
@ -287,7 +287,7 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
|
||||||
{
|
{
|
||||||
path = ResolveLibraryPath( aLibraryPath, m_project );
|
path = ResolveLibraryPath( aLibraryPath, m_project );
|
||||||
|
|
||||||
std::function<std::string( const std::string&, const std::string& )> f2 =
|
std::function<wxString( const wxString&, const wxString& )> f2 =
|
||||||
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
|
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
|
||||||
|
|
||||||
auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) ).first;
|
auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) ).first;
|
||||||
|
|
|
@ -76,9 +76,7 @@ public:
|
||||||
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
|
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
|
||||||
|
|
||||||
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject );
|
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject );
|
||||||
|
wxString ResolveEmbeddedLibraryPath( const wxString& aLibPath, const wxString& aRelativeLib );
|
||||||
std::string ResolveEmbeddedLibraryPath( const std::string& aLibPath,
|
|
||||||
const std::string& aRelativeLib );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PROJECT* m_project;
|
const PROJECT* m_project;
|
||||||
|
|
|
@ -29,8 +29,9 @@
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter,
|
std::unique_ptr<SIM_LIBRARY>
|
||||||
std::function<std::string( const std::string&, const std::string& )> *aResolver )
|
SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter,
|
||||||
|
std::function<wxString( const wxString&, const wxString& )>* aResolver )
|
||||||
{
|
{
|
||||||
std::unique_ptr<SIM_LIBRARY> library;
|
std::unique_ptr<SIM_LIBRARY> library;
|
||||||
|
|
||||||
|
@ -41,13 +42,13 @@ std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REP
|
||||||
|
|
||||||
library->m_reporter = aReporter;
|
library->m_reporter = aReporter;
|
||||||
library->m_pathResolver = aResolver;
|
library->m_pathResolver = aResolver;
|
||||||
library->ReadFile( std::string( TO_UTF8( aFilePath ) ), aReporter );
|
library->ReadFile( aFilePath, aReporter );
|
||||||
|
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SIM_LIBRARY::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
|
void SIM_LIBRARY::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
m_filePath = aFilePath;
|
m_filePath = aFilePath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,9 @@ public:
|
||||||
* @param aReporter The reporter the library reports to
|
* @param aReporter The reporter the library reports to
|
||||||
* @return The library loaded in a newly constructed object.
|
* @return The library loaded in a newly constructed object.
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<SIM_LIBRARY> Create( const wxString& aFilePath,
|
static std::unique_ptr<SIM_LIBRARY>
|
||||||
REPORTER* aReporter = nullptr,
|
Create( const wxString& aFilePath, REPORTER* aReporter,
|
||||||
std::function<std::string( const std::string&, const std::string& )>* aResolver = nullptr);
|
std::function<wxString( const wxString&, const wxString& )>* aResolver );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read library from a source file. Must be in the format appropriate to the subclass, e.g.
|
* Read library from a source file. Must be in the format appropriate to the subclass, e.g.
|
||||||
|
@ -63,15 +63,7 @@ public:
|
||||||
* @param aFilePath Path to the file.
|
* @param aFilePath Path to the file.
|
||||||
* @throw IO_ERROR on read or parsing error.
|
* @throw IO_ERROR on read or parsing error.
|
||||||
*/
|
*/
|
||||||
virtual void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) = 0;
|
virtual void ReadFile( const wxString& aFilePath, REPORTER* aReporter ) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Write library to a source file (e.g. in Spice format).
|
|
||||||
*
|
|
||||||
* @param aFilePath Path to the file.
|
|
||||||
* @throw IO_ERROR on write error.
|
|
||||||
*/
|
|
||||||
virtual void WriteFile( const std::string& aFilePath ) = 0;
|
|
||||||
|
|
||||||
SIM_MODEL* FindModel( const std::string& aModelName ) const;
|
SIM_MODEL* FindModel( const std::string& aModelName ) const;
|
||||||
|
|
||||||
|
@ -83,7 +75,7 @@ protected:
|
||||||
std::vector<std::string> m_modelNames;
|
std::vector<std::string> m_modelNames;
|
||||||
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
|
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
|
||||||
|
|
||||||
std::function<std::string( const std::string&, const std::string& )>* m_pathResolver;
|
std::function<wxString( const wxString&, const wxString& )>* m_pathResolver;
|
||||||
|
|
||||||
std::string m_filePath;
|
std::string m_filePath;
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,10 @@
|
||||||
#include <lib_pin.h>
|
#include <lib_pin.h>
|
||||||
|
|
||||||
|
|
||||||
void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
|
void SIM_LIBRARY_KIBIS::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
SIM_LIBRARY::ReadFile( aFilePath, aReporter );
|
SIM_LIBRARY::ReadFile( aFilePath, aReporter );
|
||||||
m_kibis = KIBIS( aFilePath, m_reporter );
|
m_kibis = KIBIS( aFilePath.ToStdString(), m_reporter );
|
||||||
|
|
||||||
if( !m_kibis.m_valid )
|
if( !m_kibis.m_valid )
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,10 +38,7 @@ public:
|
||||||
static constexpr auto DIFF_FIELD = "Sim.Ibis.Diff";
|
static constexpr auto DIFF_FIELD = "Sim.Ibis.Diff";
|
||||||
|
|
||||||
// @copydoc SIM_LIBRARY::ReadFile()
|
// @copydoc SIM_LIBRARY::ReadFile()
|
||||||
void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) override;
|
void ReadFile( const wxString& aFilePath, REPORTER* aReporter ) override;
|
||||||
|
|
||||||
// @copydoc SIM_LIBRARY::WriteFile()
|
|
||||||
void WriteFile( const std::string& aFilePath ) override{};
|
|
||||||
|
|
||||||
bool InitModel( SIM_MODEL_KIBIS& aModel, wxString aCompName );
|
bool InitModel( SIM_MODEL_KIBIS& aModel, wxString aCompName );
|
||||||
bool isPinDiff( const std::string& aComp, const std::string& aPinNumber ) const;
|
bool isPinDiff( const std::string& aComp, const std::string& aPinNumber ) const;
|
||||||
|
|
|
@ -33,14 +33,9 @@ SIM_LIBRARY_SPICE::SIM_LIBRARY_SPICE() :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SIM_LIBRARY_SPICE::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
|
void SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
SIM_LIBRARY::ReadFile( aFilePath, aReporter );
|
SIM_LIBRARY::ReadFile( aFilePath, aReporter );
|
||||||
m_spiceLibraryParser->ReadFile( aFilePath, aReporter );
|
m_spiceLibraryParser->ReadFile( aFilePath, aReporter );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SIM_LIBRARY_SPICE::WriteFile( const std::string& aFilePath )
|
|
||||||
{
|
|
||||||
// Not implemented yet.
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,10 +37,7 @@ public:
|
||||||
SIM_LIBRARY_SPICE();
|
SIM_LIBRARY_SPICE();
|
||||||
|
|
||||||
// @copydoc SIM_LIBRARY::ReadFile()
|
// @copydoc SIM_LIBRARY::ReadFile()
|
||||||
void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) override;
|
void ReadFile( const wxString& aFilePath, REPORTER* aReporter ) override;
|
||||||
|
|
||||||
// @copydoc SIM_LIBRARY::WriteFile()
|
|
||||||
void WriteFile( const std::string& aFilePath ) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<SPICE_LIBRARY_PARSER> m_spiceLibraryParser;
|
std::unique_ptr<SPICE_LIBRARY_PARSER> m_spiceLibraryParser;
|
||||||
|
|
|
@ -57,17 +57,16 @@ namespace SIM_LIBRARY_SPICE_PARSER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER& aReporter )
|
void SPICE_LIBRARY_PARSER::parseFile( const wxString &aFilePath, REPORTER& aReporter )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tao::pegtl::file_input in( aFilePath );
|
tao::pegtl::string_input<> in( SafeReadFile( aFilePath, wxS( "r" ) ).ToStdString(),
|
||||||
std::unique_ptr<tao::pegtl::parse_tree::node> root =
|
aFilePath.ToStdString() );
|
||||||
tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
|
auto root = tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
|
||||||
SIM_LIBRARY_SPICE_PARSER::librarySelector,
|
SIM_LIBRARY_SPICE_PARSER::librarySelector,
|
||||||
tao::pegtl::nothing,
|
tao::pegtl::nothing,
|
||||||
SIM_LIBRARY_SPICE_PARSER::control>
|
SIM_LIBRARY_SPICE_PARSER::control> ( in );
|
||||||
( in );
|
|
||||||
|
|
||||||
for( const auto& node : root->children )
|
for( const auto& node : root->children )
|
||||||
{
|
{
|
||||||
|
@ -88,14 +87,14 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER&
|
||||||
}
|
}
|
||||||
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::dotInclude>() )
|
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::dotInclude>() )
|
||||||
{
|
{
|
||||||
std::string lib = node->children.at( 0 )->string();
|
wxString lib = node->children.at( 0 )->string();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if( m_library.m_pathResolver )
|
if( m_library.m_pathResolver )
|
||||||
lib = ( *m_library.m_pathResolver )( lib, aFilePath );
|
lib = ( *m_library.m_pathResolver )( lib, aFilePath );
|
||||||
|
|
||||||
readElement( lib, aReporter );
|
parseFile( lib, aReporter );
|
||||||
}
|
}
|
||||||
catch( const IO_ERROR& e )
|
catch( const IO_ERROR& e )
|
||||||
{
|
{
|
||||||
|
@ -112,9 +111,9 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( const std::filesystem::filesystem_error& e )
|
catch( const IO_ERROR& e )
|
||||||
{
|
{
|
||||||
aReporter.Report( e.what(), RPT_SEVERITY_ERROR );
|
aReporter.Report( e.What(), RPT_SEVERITY_ERROR );
|
||||||
}
|
}
|
||||||
catch( const tao::pegtl::parse_error& e )
|
catch( const tao::pegtl::parse_error& e )
|
||||||
{
|
{
|
||||||
|
@ -123,21 +122,21 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER&
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
|
void SPICE_LIBRARY_PARSER::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
m_library.m_models.clear();
|
m_library.m_models.clear();
|
||||||
m_library.m_modelNames.clear();
|
m_library.m_modelNames.clear();
|
||||||
|
|
||||||
if( aReporter )
|
if( aReporter )
|
||||||
{
|
{
|
||||||
readElement( aFilePath, *aReporter );
|
parseFile( aFilePath, *aReporter );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wxString msg;
|
wxString msg;
|
||||||
WX_STRING_REPORTER reporter( &msg );
|
WX_STRING_REPORTER reporter( &msg );
|
||||||
|
|
||||||
readElement( aFilePath, reporter );
|
parseFile( aFilePath, reporter );
|
||||||
|
|
||||||
if( reporter.HasMessage() )
|
if( reporter.HasMessage() )
|
||||||
THROW_IO_ERROR( msg );
|
THROW_IO_ERROR( msg );
|
||||||
|
|
|
@ -40,10 +40,10 @@ public:
|
||||||
virtual ~SPICE_LIBRARY_PARSER()
|
virtual ~SPICE_LIBRARY_PARSER()
|
||||||
{};
|
{};
|
||||||
|
|
||||||
virtual void ReadFile( const std::string& aFilePath, REPORTER* aReporter );
|
virtual void ReadFile( const wxString& aFilePath, REPORTER* aReporter );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void readElement( const std::string& aFilePath, REPORTER& aReporter );
|
void parseFile( const wxString& aFilePath, REPORTER& aReporter );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SIM_LIBRARY_SPICE& m_library;
|
SIM_LIBRARY_SPICE& m_library;
|
||||||
|
|
|
@ -70,6 +70,18 @@ std::string
|
||||||
StrPrintf( const char* format, ... );
|
StrPrintf( const char* format, ... );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nominally opens a file and reads it into a string. But unlike other facilities, this handles
|
||||||
|
* mis-encded Wine-written files on macOS.
|
||||||
|
*
|
||||||
|
* @param aFilePath
|
||||||
|
* @param aReadType
|
||||||
|
* @throw IO_ERROR if the file can't be opened
|
||||||
|
* @return the file contents
|
||||||
|
*/
|
||||||
|
wxString SafeReadFile( const wxString& aFilePath, const wxString& aReadType );
|
||||||
|
|
||||||
|
|
||||||
#define LINE_READER_LINE_DEFAULT_MAX 1000000
|
#define LINE_READER_LINE_DEFAULT_MAX 1000000
|
||||||
#define LINE_READER_LINE_INITIAL_SIZE 5000
|
#define LINE_READER_LINE_INITIAL_SIZE 5000
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue