add PushReader and PopReader to DSNLEXER, make FILE_LINE_READER own its FILE*

This commit is contained in:
Dick Hollenbeck 2010-10-05 02:15:29 -05:00
parent 3335ccd98d
commit 0267b05938
8 changed files with 167 additions and 76 deletions

View File

@ -4,6 +4,29 @@ KiCad ChangeLog 2010
Please add newer entries at the top, list the date and your name with
email address.
2010-Oct-5 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
++richio:
* LINE_READER now has a GetSource() function which is used in error
reporting. This is typically the name of the file which is supplying the
lines of text, or string "clipboard" if the text is coming from the clipboard.
Derived classes FILE_LINE_READER and STRING_LINE_READER's constructors both
need an additional parameter which identifies the source.
* FILE_LINE_READER now owns the source FILE and will close it in its destructor.
This resulted in the removal of several fclose() statements that had been
there to close a file associated with a FILE_LINE_READER.
* DSNLEXER now supports an internal LINE_READER* stack which is used to handle
nested s-expression files, with the ability to resume from the proper place
in the containing file. There is now PushReader() and PopReader() functions
in DSNLEXER to handle this. No protection is provided against circular
inclusions, but this could be done by searching the stack and comparing
GetSource() values for anything already on the stack before pushing.
Each s-expression grammar is free to define one or more keywords that cause
nesting to occur. That policy choice is not part of DSNLEXER's job.
One example might be:
(inherit (footprint library_uri ftprintname))
2010-oct-03, UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
++gerbview:

View File

@ -58,24 +58,18 @@ void DSNLEXER::init()
commentsAreTokens = false;
// "start" should never change until we change the reader. The DSN
// format spec supports an include file mechanism but we can add that later
// using a std::stack to hold a stack of LINE_READERs to track nesting.
start = (char*) (*reader);
limit = start;
next = start;
}
DSNLEXER::DSNLEXER( FILE* aFile, const wxString& aFilename,
const KEYWORD* aKeywordTable, unsigned aKeywordCount ) :
keywords( aKeywordTable ),
keywordCount( aKeywordCount )
{
filename = aFilename;
reader = new FILE_LINE_READER( aFile, 4096 );
FILE_LINE_READER* fileReader = new FILE_LINE_READER( aFile, aFilename, 4096 );
PushReader( fileReader );
init();
}
@ -85,14 +79,29 @@ DSNLEXER::DSNLEXER( const std::string& aClipboardTxt,
keywords( aKeywordTable ),
keywordCount( aKeywordCount )
{
filename = _( "clipboard" );
reader = new STRING_LINE_READER( aClipboardTxt );
STRING_LINE_READER* stringReader = new STRING_LINE_READER( aClipboardTxt, _( "clipboard" ) );
PushReader( stringReader );
init();
}
void DSNLEXER::PushReader( LINE_READER* aLineReader )
{
readerStack.push_back( aLineReader );
reader = aLineReader;
start = (char*) (*aLineReader);
}
void DSNLEXER::PopReader()
{
readerStack.pop_back();
reader = &readerStack.back();
if( reader )
start = (char*) (*reader);
}
int DSNLEXER::findToken( const std::string& tok )
{
// convert to lower case once, this should be faster than using strcasecmp()
@ -207,7 +216,7 @@ bool DSNLEXER::IsSymbol( int aTok )
void DSNLEXER::ThrowIOError( wxString aText, int charOffset ) throw (IOError)
{
// append to aText, do not overwrite
aText << wxT(" ") << _("in") << wxT(" \"") << filename
aText << wxT(" ") << _("in") << wxT(" \"") << CurSource()
<< wxT("\" ") << _("on line") << wxT(" ") << reader->LineNumber()
<< wxT(" ") << _("at offset") << wxT(" ") << charOffset;

View File

@ -49,10 +49,11 @@ LINE_READER::LINE_READER( unsigned aMaxLineLength )
}
FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, unsigned aMaxLineLength ) :
LINE_READER( aMaxLineLength )
FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, const wxString& aFileName, unsigned aMaxLineLength ) :
LINE_READER( aMaxLineLength ),
fp( aFile )
{
fp = aFile;
source = aFileName;
}
@ -81,11 +82,11 @@ int FILE_LINE_READER::ReadLine() throw (IOError)
int STRING_LINE_READER::ReadLine() throw (IOError)
{
size_t nlOffset = source.find( '\n', ndx );
size_t nlOffset = lines.find( '\n', ndx );
size_t advance;
if( nlOffset == std::string::npos )
advance = source.length() - ndx;
advance = lines.length() - ndx;
else
advance = nlOffset - ndx + 1; // include the newline, so +1
@ -94,7 +95,7 @@ int STRING_LINE_READER::ReadLine() throw (IOError)
if( advance > maxLineLength )
throw IOError( _("Line length exceeded") );
wxASSERT( ndx + advance <= source.length() );
wxASSERT( ndx + advance <= lines.length() );
memcpy( line, &source[ndx], advance );

View File

@ -113,13 +113,14 @@ int WinEDA_CvpcbFrame::ReadSchematicNetlist()
return -1;
}
FILE_LINE_READER netlistReader( source, BUFFER_CHAR_SIZE );
// FILE_LINE_READER will close the file.
FILE_LINE_READER netlistReader( source, m_NetlistFileName.GetFullPath(), BUFFER_CHAR_SIZE );
char* Line = netlistReader;
/* Read the file header (must be "( { OrCAD PCB" or "({ OrCAD PCB" )
* or "# EESchema Netlist"
*/
netlistReader.ReadLine( );
netlistReader.ReadLine();
/* test for netlist type PCB2 */
idx = strnicmp( Line, "( {", 3 );
@ -137,7 +138,6 @@ int WinEDA_CvpcbFrame::ReadSchematicNetlist()
wxString msg, Lineconv = CONV_FROM_UTF8( Line );
msg.Printf( _( "Unknown file format <%s>" ), Lineconv.GetData() );
DisplayError( this, msg );
fclose( source );
return -3;
}
@ -263,8 +263,6 @@ int WinEDA_CvpcbFrame::ReadSchematicNetlist()
ReadPinConnection( netlistReader, Cmp );
}
fclose( source );
m_components.sort();
return 0;
@ -274,8 +272,8 @@ int WinEDA_CvpcbFrame::ReadSchematicNetlist()
int ReadFootprintFilterList( FILE_LINE_READER& aNetlistReader, COMPONENT_LIST& aComponentsList )
{
char* Line = aNetlistReader;
wxString CmpRef;
COMPONENT* Cmp = NULL;
wxString CmpRef;
COMPONENT* Cmp = NULL;
for( ; ; )
{
@ -318,16 +316,16 @@ int ReadFootprintFilterList( FILE_LINE_READER& aNetlistReader, COMPONENT_LIST&
int ReadPinConnection( FILE_LINE_READER& aNetlistReader, COMPONENT* Cmp )
{
int i, jj;
char* Line = aNetlistReader;
char cbuffer[BUFFER_CHAR_SIZE];
int i, jj;
char* Line = aNetlistReader;
char cbuffer[BUFFER_CHAR_SIZE];
for( ; ; )
{
/* Find beginning of description. */
for( ; ; )
{
if( aNetlistReader.ReadLine( ) == 0 )
if( aNetlistReader.ReadLine() == 0 )
return -1;
/* Remove blanks from the beginning of the line. */

View File

@ -27,6 +27,7 @@
#include <cstdio>
#include <string>
#include <boost/ptr_container/ptr_vector.hpp>
#include "fctsys.h"
@ -81,12 +82,14 @@ class DSNLEXER
char* start;
char* limit;
LINE_READER* reader;
typedef boost::ptr_vector<LINE_READER> READER_STACK;
READER_STACK readerStack; ///< owns all the LINE_READERs by pointer.
LINE_READER* reader; ///< no ownership. ownership is via readerStack.
int stringDelimiter;
bool space_in_quoted_tokens; ///< blank spaces within quoted strings
bool commentsAreTokens; ///< true if should return comments as tokens
wxString filename;
int prevTok; ///< curTok from previous NextTok() call.
int curOffset; ///< offset within current line of the current token
@ -164,9 +167,26 @@ public:
~DSNLEXER()
{
delete reader;
}
/**
* Function PushReader
* manages a stack of LINE_READERs in order to handle nested file inclusion.
* Pushes aLineReader onto the top of a stack of LINE_READERs and makes
* it the current LINE_READER with its own GetSource(), line number and line text.
*/
void PushReader( LINE_READER* aLineReader );
/**
* Function PopReader
* deletes the top most LINE_READER from an internal stack of LINE_READERs and
* in the case of FILE_LINE_READER this means the associated FILE is closed.
* The most recently used former LINE_READER on the stack becomes the
* current LINE_READER and its previous position in its input stream and the
* its latest line number should pertain.
*/
void PopReader();
// Some functions whose return value is best overloaded to return an enum
// in a derived class.
//-----<overload return values to tokens>------------------------------
@ -364,12 +384,13 @@ public:
/**
* Function CurFilename
* returns the current input filename.
* @return const wxString& - the filename.
* returns the current LINE_READER source.
* @return const wxString& - the source of the lines of text,
* e.g. a filename or "clipboard".
*/
const wxString& CurFilename()
const wxString& CurSource()
{
return filename;
return reader->GetSource();
}
/**

View File

@ -64,8 +64,8 @@ struct IOError
/**
* Class LINE_READER
* reads single lines of text into its buffer and increments a line number counter.
* It throws an exception if a line is too long.
* is an abstract class from which implementation specific LINE_READERs may
* be derived to read single lines of text and manage a line number counter.
*/
class LINE_READER
{
@ -75,8 +75,15 @@ protected:
char* line;
unsigned maxLineLength;
unsigned capacity;
wxString source; ///< origin of text lines, e.g. filename or "clipboard"
public:
/**
* Constructor LINE_READER
* builds a line reader and fixes the length of the maximum supported
* line length to @a aMaxLineLength.
*/
LINE_READER( unsigned aMaxLineLength );
virtual ~LINE_READER()
@ -94,16 +101,42 @@ public:
*/
virtual int ReadLine() throw (IOError) = 0;
/**
* Function GetSource
* returns the name of the source of the lines in an abstract sense.
* This may be a file or it may be the clipboard or any other source
* of lines of text. The returned string is useful for reporting error
* messages.
*/
const wxString& GetSource()
{
return source;
}
/**
* Operator char*
* is a casting operator that returns a char* pointer to the start of the
* line buffer.
*/
operator char* ()
{
return line;
}
/**
* Function Line Number
* returns the line number of the last line read from this LINE_READER. Lines
* start from 1.
*/
int LineNumber()
{
return lineNum;
}
/**
* Function Length
* returns the number of bytes in the last line read from this LINE_READER.
*/
unsigned Length()
{
return length;
@ -114,22 +147,32 @@ public:
/**
* Class FILE_LINE_READER
* is a LINE_READER that reads from an open file. File must be already open
* so that this class can exist without and UI policy.
* so that this class can exist without any UI policy.
*/
class FILE_LINE_READER : public LINE_READER
{
protected:
FILE* fp; ///< no ownership, no close on destruction
FILE* fp; ///< I own this file
public:
/**
* Constructor LINE_READER
* takes an open FILE and the size of the desired line buffer.
* @param aFile An open file in "ascii" mode, not binary mode.
* @param aMaxLineLength The number of bytes to use in the line buffer.
* Constructor FILE_LINE_READER
* takes an open FILE and the size of the desired line buffer and takes
* ownership of the open file, i.e. assumes the obligation to close it.
*
* @param aFile is an open file.
* @param aFileName is the name of the file for error reporting purposes.
* @param aMaxLineLength is the number of bytes to use in the line buffer.
*/
FILE_LINE_READER( FILE* aFile, unsigned aMaxLineLength );
FILE_LINE_READER( FILE* aFile, const wxString& aFileName, unsigned aMaxLineLength );
~FILE_LINE_READER()
{
if( fp )
fclose( fp );
}
/**
* Function ReadLine
@ -143,8 +186,8 @@ public:
/**
* Function Rewind
* a wrapper to the standard function rewind.
* also clear the current line number
* rewinds the file and resets the line number back to zero. Line number
* will go to 1 on first ReadLine().
*/
void Rewind()
{
@ -161,25 +204,29 @@ public:
class STRING_LINE_READER : public LINE_READER
{
protected:
std::string source;
std::string lines;
size_t ndx;
public:
/**
* Constructor STRING_LINE_READER( const std::string& aString )
*
* @param aString is a source string consisting of one or more lines
* of text, where multiple lines are separated with a '\n' character.
* The last line does not necessarily need a trailing '\n'.
* @param aSource describes the source of aString for error reporting purposes
* can be anything meaninful, such as wxT( "cliboard" ).
*/
STRING_LINE_READER( const std::string& aString ) :
STRING_LINE_READER( const std::string& aString, const wxString& aSource ) :
LINE_READER( 4096 ),
source( aString ),
lines( aString ),
ndx( 0 )
{
// Clipboard text should be nice and _use multiple lines_ so that
// we can report _line number_ oriented error messages when parsing.
// Therefore a line of 4096 characters max seems more than adequate.
source = aSource;
}
/**

View File

@ -166,6 +166,9 @@ bool WinEDA_PcbFrame::ReadPcbNetlist( const wxString& aNetlistFullFilename,
if( !netfile )
return false;
FILE_LINE_READER netlistReader( netfile, aNetlistFullFilename, BUFFER_CHAR_SIZE );
char* Line = netlistReader;
SetLastNetListRead( aNetlistFullFilename );
if( aMessageWindow )
@ -186,12 +189,10 @@ bool WinEDA_PcbFrame::ReadPcbNetlist( const wxString& aNetlistFullFilename,
wxBusyCursor dummy; // Shows an hourglass while calculating
FILE_LINE_READER netlistReader( netfile, BUFFER_CHAR_SIZE );
char* Line = netlistReader;
/* First, read the netlist: Build the list of footprints to load (new
* footprints)
*/
while( netlistReader.ReadLine( ) )
while( netlistReader.ReadLine() )
{
Text = StrPurge( Line );
@ -251,8 +252,8 @@ bool WinEDA_PcbFrame::ReadPcbNetlist( const wxString& aNetlistFullFilename,
/* Second read , All footprints are on board, one must update the schematic
* info (pad netnames) */
netlistReader.Rewind( );
while( netlistReader.ReadLine( ) )
netlistReader.Rewind();
while( netlistReader.ReadLine() )
{
Text = StrPurge( Line );
@ -312,8 +313,6 @@ bool WinEDA_PcbFrame::ReadPcbNetlist( const wxString& aNetlistFullFilename,
}
}
fclose( netfile );
// Delete footprints not found in netlist:
if( aDeleteExtraFootprints )
{
@ -794,7 +793,7 @@ int BuildFootprintsListFromNetlistFile( const wxString& aNetlistFullFilename,
if( !netfile )
return -1;
FILE_LINE_READER netlistReader( netfile, BUFFER_CHAR_SIZE );
FILE_LINE_READER netlistReader( netfile, aNetlistFullFilename, BUFFER_CHAR_SIZE );
char* Line = netlistReader;
State = 0; Comment = 0;
@ -842,8 +841,6 @@ int BuildFootprintsListFromNetlistFile( const wxString& aNetlistFullFilename,
}
}
fclose( netfile );
return nb_modules_lus;
}
@ -899,7 +896,7 @@ int ReadListeModules( const wxString& CmpFullFileName, const wxString* RefCmp,
return 0;
}
FILE_LINE_READER netlistReader( FichCmp, BUFFER_CHAR_SIZE );
FILE_LINE_READER netlistReader( FichCmp, CmpFullFileName, BUFFER_CHAR_SIZE );
char* Line = netlistReader;
while( netlistReader.ReadLine() )
@ -947,7 +944,6 @@ int ReadListeModules( const wxString& CmpFullFileName, const wxString* RefCmp,
{
if( RefCmp->CmpNoCase( refcurrcmp ) == 0 ) // Found!
{
fclose( FichCmp );
NameModule = idmod;
return 1;
}
@ -957,14 +953,12 @@ int ReadListeModules( const wxString& CmpFullFileName, const wxString* RefCmp,
if( TimeStamp->CmpNoCase( timestamp ) == 0
&& !timestamp.IsEmpty() ) // Found
{
fclose( FichCmp );
NameModule = idmod;
return 1;
}
}
}
fclose( FichCmp );
return -1;
}

View File

@ -677,8 +677,6 @@ void SPECCTRA_DB::readTIME( time_t* time_stamp ) throw( IOError )
void SPECCTRA_DB::LoadPCB( const wxString& filename ) throw( IOError )
{
wxFFile file;
FILE* fp = wxFopen( filename, wxT("r") );
if( !fp )
@ -686,12 +684,10 @@ void SPECCTRA_DB::LoadPCB( const wxString& filename ) throw( IOError )
ThrowIOError( _("Unable to open file \"%s\""), GetChars(filename) );
}
file.Attach( fp ); // "exception safe" way to close the file.
delete lexer;
lexer = 0;
lexer = new DSNLEXER( file.fp(), filename, SPECCTRA_DB::keywords, SPECCTRA_DB::keywordCount );
lexer = new DSNLEXER( fp, filename, SPECCTRA_DB::keywords, SPECCTRA_DB::keywordCount );
if( nextTok() != T_LEFT )
expecting( T_LEFT );
@ -702,13 +698,14 @@ void SPECCTRA_DB::LoadPCB( const wxString& filename ) throw( IOError )
SetPCB( new PCB() );
doPCB( pcb );
delete lexer; // close the file.
lexer = 0;
}
void SPECCTRA_DB::LoadSESSION( const wxString& filename ) throw( IOError )
{
wxFFile file;
FILE* fp = wxFopen( filename, wxT("r") );
if( !fp )
@ -716,12 +713,10 @@ void SPECCTRA_DB::LoadSESSION( const wxString& filename ) throw( IOError )
ThrowIOError( _("Unable to open file \"%s\""), GetChars(filename) );
}
file.Attach( fp ); // "exception safe" way to close the file.
delete lexer;
lexer = 0;
lexer = new DSNLEXER( file.fp(), filename, SPECCTRA_DB::keywords, SPECCTRA_DB::keywordCount );
lexer = new DSNLEXER( fp, filename, SPECCTRA_DB::keywords, SPECCTRA_DB::keywordCount );
if( nextTok() != T_LEFT )
expecting( T_LEFT );
@ -732,6 +727,9 @@ void SPECCTRA_DB::LoadSESSION( const wxString& filename ) throw( IOError )
SetSESSION( new SESSION() );
doSESSION( session );
delete lexer; // close the file.
lexer = 0;
}