Commit a6e21516 authored by Dick Hollenbeck's avatar Dick Hollenbeck
Browse files

implement more of SCH::LIB_TABLE, start SCH::LPID, enhance richio

parents 7ca0b717 a7c11a0b
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -65,7 +65,7 @@ DSNLEXER::DSNLEXER( const KEYWORD* aKeywordTable, unsigned aKeywordCount,
    keywords( aKeywordTable ),
    keywords( aKeywordTable ),
    keywordCount( aKeywordCount )
    keywordCount( aKeywordCount )
{
{
    FILE_LINE_READER* fileReader = new FILE_LINE_READER( aFile, aFilename, 4096 );
    FILE_LINE_READER* fileReader = new FILE_LINE_READER( aFile, aFilename );
    PushReader( fileReader );
    PushReader( fileReader );
    init();
    init();
}
}
+37 −2
Original line number Original line Diff line number Diff line
@@ -82,11 +82,23 @@ void LINE_READER::expandCapacity( unsigned newsize )
}
}




FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, const wxString& aFileName, unsigned aMaxLineLength ) :
FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, const wxString& aFileName,
                    bool doOwn,
                    unsigned aStartingLineNumber,
                    unsigned aMaxLineLength ) :
    LINE_READER( aMaxLineLength ),
    LINE_READER( aMaxLineLength ),
    iOwn( doOwn ),
    fp( aFile )
    fp( aFile )
{
{
    source  = aFileName;
    source  = aFileName;
    lineNum = aStartingLineNumber;
}


FILE_LINE_READER::~FILE_LINE_READER()
{
    if( iOwn && fp )
        fclose( fp );
}
}




@@ -117,6 +129,29 @@ unsigned FILE_LINE_READER::ReadLine() throw( IO_ERROR )
}
}




STRING_LINE_READER::STRING_LINE_READER( const std::string& aString, const wxString& aSource ) :
    LINE_READER( LINE_READER_LINE_DEFAULT_MAX ),
    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.
    source = aSource;
}


STRING_LINE_READER::STRING_LINE_READER( const STRING_LINE_READER& aStartingPoint ) :
    LINE_READER( LINE_READER_LINE_DEFAULT_MAX ),
    lines( aStartingPoint.lines ),
    ndx( aStartingPoint.ndx )
{
    // since we are keeping the same "source" name, for error reporting purposes
    // we need to have the same notion of line number and offset.

    source  = aStartingPoint.source;
    lineNum = aStartingPoint.lineNum;
}

unsigned STRING_LINE_READER::ReadLine() throw( IO_ERROR )
unsigned STRING_LINE_READER::ReadLine() throw( IO_ERROR )
{
{
    size_t  nlOffset = lines.find( '\n', ndx );
    size_t  nlOffset = lines.find( '\n', ndx );
+28 −19
Original line number Original line Diff line number Diff line
@@ -53,7 +53,7 @@ class LINE_READER
{
{
protected:
protected:
    unsigned    length;         ///< no. bytes in line before trailing nul.
    unsigned    length;         ///< no. bytes in line before trailing nul.
    int         lineNum;
    unsigned    lineNum;


    char*       line;           ///< the read line of UTF8 text
    char*       line;           ///< the read line of UTF8 text
    unsigned    capacity;       ///< no. bytes allocated for line.
    unsigned    capacity;       ///< no. bytes allocated for line.
@@ -115,7 +115,7 @@ public:
     * returns the line number of the last line read from this LINE_READER.  Lines
     * returns the line number of the last line read from this LINE_READER.  Lines
     * start from 1.
     * start from 1.
     */
     */
    int LineNumber() const
    unsigned LineNumber() const
    {
    {
        return lineNum;
        return lineNum;
    }
    }
@@ -140,7 +140,8 @@ class FILE_LINE_READER : public LINE_READER
{
{
protected:
protected:


    FILE*   fp;     ///< I own this file
    bool    iOwn;   ///< if I own the file, I'll promise to close it, else not.
    FILE*   fp;     ///< I may own this file, but might not.


public:
public:


@@ -151,15 +152,23 @@ public:
     *
     *
     * @param aFile is an open file.
     * @param aFile is an open file.
     * @param aFileName is the name of the file for error reporting purposes.
     * @param aFileName is the name of the file for error reporting purposes.
     * @param doOwn if true, means I should close the open file, else not.
     * @param aStartingLineNumber is the initial line number to report on error, and is
     *  accessible here for the case where multiple DSNLEXERs are reading from the
     *  same file in sequence, all from the same open file (with @a doOwn = false).
     *  Internally it is incremented by one after each ReadLine(), so the first
     *  reported line number will always be one greater than what is provided here.
     * @param aMaxLineLength is the number of bytes to use in the line buffer.
     * @param aMaxLineLength is the number of bytes to use in the line buffer.
     */
     */
    FILE_LINE_READER( FILE* aFile,  const wxString& aFileName, unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );
    FILE_LINE_READER( FILE* aFile, const wxString& aFileName, bool doOwn = true,
            unsigned aStartingLineNumber = 0,
            unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );


    ~FILE_LINE_READER()
    /**
    {
     * Destructor
        if( fp )
     * may or may not close the open file, depending on @a doOwn in constructor.
            fclose( fp );
     */
    }
    ~FILE_LINE_READER();


    unsigned ReadLine() throw( IO_ERROR );   // see LINE_READER::ReadLine() description
    unsigned ReadLine() throw( IO_ERROR );   // see LINE_READER::ReadLine() description


@@ -198,15 +207,15 @@ public:
     * @param aSource describes the source of aString for error reporting purposes
     * @param aSource describes the source of aString for error reporting purposes
     *  can be anything meaninful, such as wxT( "clipboard" ).
     *  can be anything meaninful, such as wxT( "clipboard" ).
     */
     */
    STRING_LINE_READER( const std::string& aString, const wxString& aSource ) :
    STRING_LINE_READER( const std::string& aString, const wxString& aSource );
        LINE_READER( LINE_READER_LINE_DEFAULT_MAX ),

        lines( aString ),
    /**
        ndx( 0 )
     * Constructor STRING_LINE_READER( const STRING_LINE_READER& )
    {
     * allows for a continuation of the reading of a stream started by another
        // Clipboard text should be nice and _use multiple lines_ so that
     * STRING_LINE_READER.  Any stream offset and source name are used from
        // we can report _line number_ oriented error messages when parsing.
     * @a aStartingPoint.
        source = aSource;
     */
    }
    STRING_LINE_READER( const STRING_LINE_READER& aStartingPoint );


    unsigned ReadLine() throw( IO_ERROR );    // see LINE_READER::ReadLine() description
    unsigned ReadLine() throw( IO_ERROR );    // see LINE_READER::ReadLine() description
};
};
+0 −152
Original line number Original line Diff line number Diff line
@@ -371,158 +371,6 @@ const STRING StrEmpty = "";
/** @} exception_types Exception Types */
/** @} exception_types Exception Types */





/**
 * Class LPID (aka GUID)
 * is a Logical Part ID and consists of various portions much like a URI.  It
 * relies heavily on a logical library name to hide where actual physical library
 * sources reside.  Its static functions serve as managers of the "library table" to
 * map logical library names to actual library sources.
 * <p>
 * Example LPID string:
 * "kicad:passives/R/rev6".
 * <p>
 * <ul>
 * <li> "kicad" is the logical library name.
 * <li> "passives" is the category.
 * <li> "passives/R" is the partname.
 * <li> "rev6" is the revision number, which is optional.  If missing then its
 *      delimiter should also not be present.
 * </ul>
 * <p>
 * This class owns the <b>library table</b>, which is like fstab in concept and maps logical
 * library name to library URI, type, and options. It has the following columns:
 * <ul>
 * <li> Logical Library Name
 * <li> Library Type
 * <li> Library URI.  The full URI to the library source, form dependent on Type.
 * <li> Options, used for access, such as password
 * </ul>
 * <p>
 * For now, the Library Type can be one of:
 * <ul>
 * <li> "dir"
 * <li> "schematic"  i.e. a parts list from another schematic.
 * <li> "subversion"
 * <li> "bazaar"
 * <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> "file://home/user/kicadwork/jtagboard.sch"
 * <li> "svn://kicad.org/partlib/trunk"
 * <li> "http://kicad.org/partlib"
 * </ul>
 * <p>
 * The applicable library table is built up from several additive rows (table fragments),
 * and the final table is a merging of the table fragments. Two anticipated sources of
 * the rows are a personal table, and a schematic resident table.  The schematic
 * resident table rows are considered a higher priority in the final dynamically
 * assembled library table. A row in the schematic contribution to the library table
 * will take precedence over the personal table if there is a collision on logical
 * library name, otherwise the rows simply combine without issue to make up the
 * applicable library table.
 */
class LPID  // aka GUID
{
public:
    /**
     * Constructor LPID
     * takes aLPID string and parses it.  A typical LPID string uses a logical
     * library name followed by a part name.
     * e.g.: "kicad:passives/R/rev2", or
     * e.g.: "mylib:R33"
     */
    LPID( const STRING& aLPID ) throw( PARSE_ERROR );

    /**
     * Function GetLogLib
     * returns the logical library portion of a LPID.  There is not Set accessor
     * for this portion since it comes from the library table and is considered
     * read only here.
     */
    STRING  GetLogLib() const;

    /**
     * Function GetCategory
     * returns the category of this part id, "passives" in the example at the
     * top of the class description.
     */
    STRING  GetCategory() const;

    /**
     * Function SetCategory
     * overrides the category portion of the LPID to @a aCategory and is typically
     * either the empty string or a single word like "passives".
     */
    void SetCategory( const STRING& aCategory );

    /**
     * Function GetRevision
     * returns the revision portion of the LPID or StrEmpty if none.
     */
    STRING GetRevision() const;

    /**
     * Function SetRevision
     * overrides the revision portion of the LPID to @a aRevision and must
     * be in the form "rev<num>" where "<num>" is "1", "2", etc.
     */
    void SetRevision( const STRING& aRevision );

    /**
     * Function GetFullText
     * returns the full text of the LPID.
     */
    STRING  GetFullText() const;


    //-----<statics>-----------------------------------------------------

    /**
     * Function GetLogicalLibraries
     * returns the logical library names, all of them that are in the
     * library table.
     * @param aSchematic provides access to the full library table inclusive
     *  of the schematic contribution, or may be NULL to exclude the schematic rows.
     */
    static STRINGS GetLogicalLibraries( SCHEMATIC* aSchematic=NULL );

    /**
     * Function GetLibraryURI
     * returns the full library path from a logical library name.
     * @param aLogicalLibraryName is the short name for the library of interest.
     * @param aSchematic provides access to the full library table inclusive
     *  of the schematic contribution, or may be NULL to exclude the schematic rows.
     */
    static STRING  GetLibraryURI( const STRING& aLogicalLibraryName,
                        SCHEMATIC* aSchematic=NULL ) const;

    /**
     * Function GetLibraryType
     * returns the type of a logical library.
     * @param aLogicalLibraryName is the short name for the library of interest.
     * @param aSchematic provides access to the full library table inclusive
     *  of the schematic contribution, or may be NULL to exclude the schematic rows.
     */
    static STRING GetLibraryType( const STRING& aLogicalLibraryName,
                        SCHEMATIC* aSchematic=NULL ) const;

    /**
     * Function GetOptions
     * returns the options string for \a aLogicalLibraryName.
     * @param aLogicalLibraryName is the short name for the library of interest.
     * @param aSchematic provides access to the full library table inclusive
     *  of the schematic contribution, or may be NULL to exclude the schematic rows.
     */
    static STRING GetPassword( const STRING& aLogicalLibraryName,
                        SCHEMATIC* aSchematic=NULL ) const;
};


/**
/**
 * Class SVN_LIB_SOURCE
 * Class SVN_LIB_SOURCE
 * implements a LIB_SOURCE in a subversion repository.
 * implements a LIB_SOURCE in a subversion repository.
+111 −15
Original line number Original line Diff line number Diff line
@@ -30,8 +30,10 @@ using namespace std;
using namespace SCH;
using namespace SCH;




LIB_TABLE::LIB_TABLE( LIB_TABLE* aFallBackTable )
LIB_TABLE::LIB_TABLE( LIB_TABLE* aFallBackTable ) :
    fallBack( aFallBackTable )
{
{
    /* not copying fall back, simply search it separately if "logicalName not found".
    if( aFallBackTable )
    if( aFallBackTable )
    {
    {
        const ROWS& t = aFallBackTable->rows;
        const ROWS& t = aFallBackTable->rows;
@@ -39,12 +41,12 @@ LIB_TABLE::LIB_TABLE( LIB_TABLE* aFallBackTable )
        for( ROWS_CITER it = t.begin();  it != t.end();  ++it )
        for( ROWS_CITER it = t.begin();  it != t.end();  ++it )
        {
        {
            // our rows are empty, expect no collisions here
            // our rows are empty, expect no collisions here
            auto_ptr<ROW>   row( new ROW( *it ) );
            auto_ptr<ROW> row( new ROW( *it->second ) );

            row->owner = this;
            row->owner = this;
            rows.insert( row.release() );
            insert( row );
        }
        }
    }
    }
    */
}
}




@@ -126,18 +128,89 @@ void LIB_TABLE::Parse( SCH_LIB_TABLE_LEXER* in ) throw( IO_ERROR )
        in->NeedRIGHT();
        in->NeedRIGHT();
        in->NeedRIGHT();            // teriminate the (lib..)
        in->NeedRIGHT();            // teriminate the (lib..)


        rows.insert( row.release() );
        // all logicalNames within this table fragment must be unique, so we do not
        // replace.  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( !InsertLib( row ) )
        {
            char    buf[300];

            snprintf( buf, sizeof(buf),
                "'%s' is a duplicate logical lib name",
                row->logicalName.c_str() );
            throw IO_ERROR( buf );
        }
    }
    }
    return;
    return;
}
}




#if 1
void LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const
    throw( IO_ERROR )
{
    out->Print( nestLevel, "(lib_table\n" );
    for( ROWS_CITER it = rows.begin();  it != rows.end();  ++it )
        it->second->Format( out, nestLevel+1 );
    out->Print( nestLevel, ")\n" );
}


int main( int argc, char** argv )
void 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",
        logicalName.c_str(), libType.c_str(), fullURI.c_str(), options.c_str() );
}


const LIB_TABLE::ROW* LIB_TABLE::FindLib( const STRING& aLogicalName )
{
    // 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.

    ROWS_CITER  it = rows.find( aLogicalName );

    if( it != rows.end() )
    {
        // reference: http://myitcorner.com/blog/?p=361
        return (const LIB_TABLE::ROW*) it->second;  // found
    }

    // not found, search fall back table
    if( fallBack )
        return fallBack->FindLib( aLogicalName );

    return 0;   // not found
}


bool LIB_TABLE::InsertLib( auto_ptr<ROW>& aRow, bool doReplace )
{
    ROWS_ITER it = rows.find( aRow->logicalName );

    if( doReplace || it == rows.end() )
    {
        // be careful here, key is needed because aRow can be
        // release()ed before logicalName is captured.
        const STRING&   key = aRow->logicalName;
        rows.insert( key, aRow );
        return true;
    }

    return false;
}


#if 1 && defined(DEBUG)

// build this with a Debug CMAKE_BUILD_TYPE

void LIB_TABLE::Test()
{
{
    // the null string is not really a legal DSN token since any double quotes
    // the null string is not really a legal DSN token since any double quotes
    // as assumed to be a single quote.  To pass an empty string, we pass " "
    // are assumed to be a single quote.  To pass an empty string, we pass " "
    // to (options " ")
    // to (options " ")
    SCH_LIB_TABLE_LEXER  slr(
    SCH_LIB_TABLE_LEXER  slr(
        "(lib_table \n"
        "(lib_table \n"
@@ -148,16 +221,14 @@ int main( int argc, char** argv )
        wxT( "inline text" )        // source
        wxT( "inline text" )        // source
        );
        );


    LIB_TABLE   lib_table;

    // read the "( lib_table" pair of tokens

    try
    try
    {
    {
        // read the "( lib_table" pair of tokens
        slr.NextTok();
        slr.NextTok();
        slr.NextTok();
        slr.NextTok();


        lib_table.Parse( &slr );
        // parse the rest of input to slr
        Parse( &slr );
    }
    }


    catch( std::exception& ex )
    catch( std::exception& ex )
@@ -167,11 +238,36 @@ int main( int argc, char** argv )


    catch( IO_ERROR ioe )
    catch( IO_ERROR ioe )
    {
    {
        printf( "caught\n" );
        printf( "exception: %s\n", (const char*) wxConvertWX2MB( ioe.errorText ) );
        printf( "exception: %s\n", (const char*) wxConvertWX2MB( ioe.errorText ) );
    }
    }


    lib_table.Show();
    STRING_FORMATTER    sf;

    Format( &sf, 0 );

    printf( "test 'Parse() <-> Format()' round tripping:\n" );
    printf( "%s", sf.GetString().c_str() );

    printf( "\ntest a lookup of 'www':\n" );
    sf.Clear();

    const LIB_TABLE::ROW* www = FindLib( "www" );
    if( www )
    {
        // found, print it just to prove it.
        www->Format( &sf, 1 );
        printf( "%s", sf.GetString().c_str() );
    }
    else
        printf( "not found\n" );
}


int main( int argc, char** argv )
{
    LIB_TABLE   lib_table;

    lib_table.Test();


    return 0;
    return 0;
}
}
Loading