Loading new/sch_dir_lib_source.cpp +88 −44 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ using namespace SCH; #include <unistd.h> #include <unistd.h> #include <fcntl.h> #include <fcntl.h> #include <errno.h> #include <errno.h> #include <assert.h> #include <vector> #include <vector> using namespace std; using namespace std; Loading Loading @@ -159,13 +160,19 @@ 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 ) { return endsWithRev( aPartName.c_str(), aPartName.c_str()+aPartName.size(), separator ); } // see struct BY_REV // see struct BY_REV bool BY_REV::operator() ( const STRING& s1, const STRING& s2 ) const 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.c_str(), s1.c_str()+s1.size(), '/' ); const char* rev1 = endsWithRev( s1, '/' ); const char* rev2 = endsWithRev( s2.c_str(), s2.c_str()+s2.size(), '/' ); 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(); Loading Loading @@ -259,7 +266,7 @@ STRING DIR_LIB_SOURCE::makeFileName( const STRING& aPartName ) STRING fileName = sourceURI + "/"; STRING fileName = sourceURI + "/"; const char* rev = endsWithRev( aPartName.c_str(), aPartName.c_str()+aPartName.size(), '/' ); const char* rev = endsWithRev( aPartName, '/' ); if( rev ) if( rev ) { { Loading @@ -278,14 +285,14 @@ STRING DIR_LIB_SOURCE::makeFileName( const STRING& aPartName ) } } void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) throw( IO_ERROR ) void DIR_LIB_SOURCE::readString( STRING* aResult, const STRING& aFileName ) throw( IO_ERROR ) { { FILE_WRAP fw = open( aFilename.c_str(), O_RDONLY ); FILE_WRAP fw = open( aFileName.c_str(), O_RDONLY ); if( fw == -1 ) if( fw == -1 ) { { 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.c_str() ) ); throw( IO_ERROR( msg.c_str() ) ); } } Loading @@ -296,7 +303,7 @@ void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) // sanity check on file size // sanity check on file size if( fs.st_size > (1*1024*1024) ) if( fs.st_size > (1*1024*1024) ) { { STRING msg = aFilename; STRING msg = aFileName; msg += " seems too big. ( > 1 mbyte )"; msg += " seems too big. ( > 1 mbyte )"; throw IO_ERROR( msg.c_str() ); throw IO_ERROR( msg.c_str() ); } } Loading @@ -310,7 +317,7 @@ void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) if( count != (int) fs.st_size ) if( count != (int) fs.st_size ) { { STRING msg = strerror( errno ); STRING msg = strerror( errno ); msg += "; cannot read file " + aFilename; msg += "; cannot read file " + aFileName; throw( IO_ERROR( msg.c_str() ) ); throw( IO_ERROR( msg.c_str() ) ); } } Loading Loading @@ -358,42 +365,42 @@ DIR_LIB_SOURCE::~DIR_LIB_SOURCE() void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory ) void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory ) throw( IO_ERROR ) throw( IO_ERROR ) { { PN_ITER limit = aCategory.size() ? partnames.lower_bound( aCategory + char( '/' + 1 ) ) : partnames.end(); PN_ITER it = aCategory.size() ? partnames.lower_bound( aCategory + "/" ) : partnames.begin(); aResults->clear(); aResults->clear(); if( aCategory.size() ) if( useVersioning ) { { STRING lower = aCategory + "/"; STRING partName; STRING upper = aCategory + char( '/' + 1 ); PART_CACHE::const_iterator limit = partnames.upper_bound( upper ); for( PART_CACHE::const_iterator it = partnames.lower_bound( lower ); it!=limit; ++it ) while( it != limit ) { { /* const char* rev = endsWithRev( *it, '/' ); const char* start = it->c_str(); size_t len = it->size(); if( endsWithRev( start, start+len, '/' ) ) // all cached partnames have a rev string in useVersioning mode continue; assert( rev ); */ aResults->push_back( *it ); // partName is substring which omits the rev AND the rev separator partName.assign( *it, 0, rev - it->c_str() - 1 ); aResults->push_back( partName ); // skip over all other versions of the same partName. it = partnames.lower_bound( partName + char( '/' + 1 ) ); } } } } else else { { for( PART_CACHE::const_iterator it = partnames.begin(); it!=partnames.end(); ++it ) while( it != limit ) { aResults->push_back( *it++ ); /* const char* start = it->c_str(); size_t len = it->size(); if( !endsWithRev( start, start+len, '/' ) ) continue; */ aResults->push_back( *it ); } } } } } Loading @@ -401,25 +408,53 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev ) void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev ) throw( IO_ERROR ) throw( IO_ERROR ) { { STRING partname = aPartName; STRING fileName; STRING partName = aPartName; // appended with aRev too if not empty const char* rev = endsWithRev( partName, '/' ); if( aRev.size() ) if( aRev.size() ) partname += "/" + aRev; { if( rev ) // a supplied rev replaces any in aPartName partName.resize( rev - partName.c_str() - 1 ); partName += "/" + aRev; PART_CACHE::const_iterator it = partnames.find( partname ); rev = endsWithRev( partName, '/' ); } // partName is the exact part name we need here, or if rev is NULL, // then look for the highest numbered revision. if( rev ) { PN_ITER it = partnames.find( partName ); if( it == partnames.end() ) // part not found if( it == partnames.end() ) // part not found { { partname += " not found."; partName += " not found."; throw IO_ERROR( partname.c_str() ); throw IO_ERROR( partName.c_str() ); } readString( aResult, makeFileName( partName ) ); } } else { STRING search = partName + '/'; // create a fileName for the sweet string // no rev on partName string. First the first, which should be STRING fileName = makeFileName( aPartName ); // the highnest numbered rev because of BY_REV compare method. PN_ITER it = partnames.upper_bound( search ); // @todo what about aRev?, and define the public API wrt to aRev better. // verify that this one that is greater than partName is a match and not // some unrelated name that is larger. if( it == partnames.end() || it->compare( 0, search.size(), search ) != 0 ) { partName += " rev not found."; throw IO_ERROR( partName.c_str() ); } readSExpression( aResult, fileName ); readString( aResult, makeFileName( *it ) ); } } } Loading Loading @@ -539,6 +574,8 @@ int main( int argc, char** argv ) try try { { STRINGS::const_iterator pn; // DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "" ); // DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "" ); DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "useVersioning" ); DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "useVersioning" ); Loading @@ -555,6 +592,13 @@ int main( int argc, char** argv ) uut.ReadParts( &sweets, partnames ); uut.ReadParts( &sweets, partnames ); printf( "\nSweets for Category = 'Category' parts:\n" ); pn = partnames.begin(); for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) { printf( " %s: %s", pn->c_str(), it->c_str() ); } // fetch the part names for ALL categories. // fetch the part names for ALL categories. uut.GetCategoricalPartNames( &partnames ); uut.GetCategoricalPartNames( &partnames ); Loading @@ -567,7 +611,7 @@ int main( int argc, char** argv ) uut.ReadParts( &sweets, partnames ); uut.ReadParts( &sweets, partnames ); printf( "\nSweets for ALL parts:\n" ); printf( "\nSweets for ALL parts:\n" ); STRINGS::const_iterator pn = partnames.begin(); pn = partnames.begin(); for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) { { printf( " %s: %s", pn->c_str(), it->c_str() ); printf( " %s: %s", pn->c_str(), it->c_str() ); Loading new/sch_dir_lib_source.h +6 −4 Original line number Original line Diff line number Diff line Loading @@ -77,10 +77,12 @@ class DIR_LIB_SOURCE : public LIB_SOURCE /// and some of which may have legal "revN[N..]" type strings. /// and some of which may have legal "revN[N..]" type strings. PART_CACHE partnames; PART_CACHE partnames; typedef PART_CACHE::const_iterator PN_ITER; /// categories which we expect to find in the set of @a partnames /// categories which we expect to find in the set of @a partnames NAME_CACHE categories; NAME_CACHE categories; std::vector<char> readBuffer; ///< used by readSExpression() std::vector<char> readBuffer; ///< used by readString() /** /** * Function cache * Function cache Loading Loading @@ -109,10 +111,10 @@ class DIR_LIB_SOURCE : public LIB_SOURCE bool makePartName( STRING* aPartName, const char* aEntry, const STRING& aCategory ); bool makePartName( STRING* aPartName, const char* aEntry, const STRING& aCategory ); /** /** * Function readSExpression * Function readString * reads an s-expression into aResult. Candidate for virtual function later. * reads a Sweet string into aResult. Candidate for virtual function later. */ */ void readSExpression( STRING* aResult, const STRING& aNameSpec ) throw( IO_ERROR ); void readString( STRING* aResult, const STRING& aFileName ) throw( IO_ERROR ); /** /** * Function cacheOneDir * Function cacheOneDir Loading new/sch_lib.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -90,7 +90,8 @@ protected: ///< derived classes must implement * Function ReadParts * Function ReadParts * fetches the s-expressions for each part given in @a aPartNames, into @a aResults, * fetches the s-expressions for each part given in @a aPartNames, into @a aResults, * honoring the array indices respectfully. * honoring the array indices respectfully. * @param aPartNames is a list of part names, one name per list element. * @param aPartNames is a list of part names, one name per list element. If a part name * 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( STRINGS* aResults, const STRINGS& aPartNames ) Loading Loading
new/sch_dir_lib_source.cpp +88 −44 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ using namespace SCH; #include <unistd.h> #include <unistd.h> #include <fcntl.h> #include <fcntl.h> #include <errno.h> #include <errno.h> #include <assert.h> #include <vector> #include <vector> using namespace std; using namespace std; Loading Loading @@ -159,13 +160,19 @@ 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 ) { return endsWithRev( aPartName.c_str(), aPartName.c_str()+aPartName.size(), separator ); } // see struct BY_REV // see struct BY_REV bool BY_REV::operator() ( const STRING& s1, const STRING& s2 ) const 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.c_str(), s1.c_str()+s1.size(), '/' ); const char* rev1 = endsWithRev( s1, '/' ); const char* rev2 = endsWithRev( s2.c_str(), s2.c_str()+s2.size(), '/' ); 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(); Loading Loading @@ -259,7 +266,7 @@ STRING DIR_LIB_SOURCE::makeFileName( const STRING& aPartName ) STRING fileName = sourceURI + "/"; STRING fileName = sourceURI + "/"; const char* rev = endsWithRev( aPartName.c_str(), aPartName.c_str()+aPartName.size(), '/' ); const char* rev = endsWithRev( aPartName, '/' ); if( rev ) if( rev ) { { Loading @@ -278,14 +285,14 @@ STRING DIR_LIB_SOURCE::makeFileName( const STRING& aPartName ) } } void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) throw( IO_ERROR ) void DIR_LIB_SOURCE::readString( STRING* aResult, const STRING& aFileName ) throw( IO_ERROR ) { { FILE_WRAP fw = open( aFilename.c_str(), O_RDONLY ); FILE_WRAP fw = open( aFileName.c_str(), O_RDONLY ); if( fw == -1 ) if( fw == -1 ) { { 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.c_str() ) ); throw( IO_ERROR( msg.c_str() ) ); } } Loading @@ -296,7 +303,7 @@ void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) // sanity check on file size // sanity check on file size if( fs.st_size > (1*1024*1024) ) if( fs.st_size > (1*1024*1024) ) { { STRING msg = aFilename; STRING msg = aFileName; msg += " seems too big. ( > 1 mbyte )"; msg += " seems too big. ( > 1 mbyte )"; throw IO_ERROR( msg.c_str() ); throw IO_ERROR( msg.c_str() ); } } Loading @@ -310,7 +317,7 @@ void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) if( count != (int) fs.st_size ) if( count != (int) fs.st_size ) { { STRING msg = strerror( errno ); STRING msg = strerror( errno ); msg += "; cannot read file " + aFilename; msg += "; cannot read file " + aFileName; throw( IO_ERROR( msg.c_str() ) ); throw( IO_ERROR( msg.c_str() ) ); } } Loading Loading @@ -358,42 +365,42 @@ DIR_LIB_SOURCE::~DIR_LIB_SOURCE() void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory ) void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory ) throw( IO_ERROR ) throw( IO_ERROR ) { { PN_ITER limit = aCategory.size() ? partnames.lower_bound( aCategory + char( '/' + 1 ) ) : partnames.end(); PN_ITER it = aCategory.size() ? partnames.lower_bound( aCategory + "/" ) : partnames.begin(); aResults->clear(); aResults->clear(); if( aCategory.size() ) if( useVersioning ) { { STRING lower = aCategory + "/"; STRING partName; STRING upper = aCategory + char( '/' + 1 ); PART_CACHE::const_iterator limit = partnames.upper_bound( upper ); for( PART_CACHE::const_iterator it = partnames.lower_bound( lower ); it!=limit; ++it ) while( it != limit ) { { /* const char* rev = endsWithRev( *it, '/' ); const char* start = it->c_str(); size_t len = it->size(); if( endsWithRev( start, start+len, '/' ) ) // all cached partnames have a rev string in useVersioning mode continue; assert( rev ); */ aResults->push_back( *it ); // partName is substring which omits the rev AND the rev separator partName.assign( *it, 0, rev - it->c_str() - 1 ); aResults->push_back( partName ); // skip over all other versions of the same partName. it = partnames.lower_bound( partName + char( '/' + 1 ) ); } } } } else else { { for( PART_CACHE::const_iterator it = partnames.begin(); it!=partnames.end(); ++it ) while( it != limit ) { aResults->push_back( *it++ ); /* const char* start = it->c_str(); size_t len = it->size(); if( !endsWithRev( start, start+len, '/' ) ) continue; */ aResults->push_back( *it ); } } } } } Loading @@ -401,25 +408,53 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev ) void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev ) throw( IO_ERROR ) throw( IO_ERROR ) { { STRING partname = aPartName; STRING fileName; STRING partName = aPartName; // appended with aRev too if not empty const char* rev = endsWithRev( partName, '/' ); if( aRev.size() ) if( aRev.size() ) partname += "/" + aRev; { if( rev ) // a supplied rev replaces any in aPartName partName.resize( rev - partName.c_str() - 1 ); partName += "/" + aRev; PART_CACHE::const_iterator it = partnames.find( partname ); rev = endsWithRev( partName, '/' ); } // partName is the exact part name we need here, or if rev is NULL, // then look for the highest numbered revision. if( rev ) { PN_ITER it = partnames.find( partName ); if( it == partnames.end() ) // part not found if( it == partnames.end() ) // part not found { { partname += " not found."; partName += " not found."; throw IO_ERROR( partname.c_str() ); throw IO_ERROR( partName.c_str() ); } readString( aResult, makeFileName( partName ) ); } } else { STRING search = partName + '/'; // create a fileName for the sweet string // no rev on partName string. First the first, which should be STRING fileName = makeFileName( aPartName ); // the highnest numbered rev because of BY_REV compare method. PN_ITER it = partnames.upper_bound( search ); // @todo what about aRev?, and define the public API wrt to aRev better. // verify that this one that is greater than partName is a match and not // some unrelated name that is larger. if( it == partnames.end() || it->compare( 0, search.size(), search ) != 0 ) { partName += " rev not found."; throw IO_ERROR( partName.c_str() ); } readSExpression( aResult, fileName ); readString( aResult, makeFileName( *it ) ); } } } Loading Loading @@ -539,6 +574,8 @@ int main( int argc, char** argv ) try try { { STRINGS::const_iterator pn; // DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "" ); // DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "" ); DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "useVersioning" ); DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", "useVersioning" ); Loading @@ -555,6 +592,13 @@ int main( int argc, char** argv ) uut.ReadParts( &sweets, partnames ); uut.ReadParts( &sweets, partnames ); printf( "\nSweets for Category = 'Category' parts:\n" ); pn = partnames.begin(); for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) { printf( " %s: %s", pn->c_str(), it->c_str() ); } // fetch the part names for ALL categories. // fetch the part names for ALL categories. uut.GetCategoricalPartNames( &partnames ); uut.GetCategoricalPartNames( &partnames ); Loading @@ -567,7 +611,7 @@ int main( int argc, char** argv ) uut.ReadParts( &sweets, partnames ); uut.ReadParts( &sweets, partnames ); printf( "\nSweets for ALL parts:\n" ); printf( "\nSweets for ALL parts:\n" ); STRINGS::const_iterator pn = partnames.begin(); pn = partnames.begin(); for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) { { printf( " %s: %s", pn->c_str(), it->c_str() ); printf( " %s: %s", pn->c_str(), it->c_str() ); Loading
new/sch_dir_lib_source.h +6 −4 Original line number Original line Diff line number Diff line Loading @@ -77,10 +77,12 @@ class DIR_LIB_SOURCE : public LIB_SOURCE /// and some of which may have legal "revN[N..]" type strings. /// and some of which may have legal "revN[N..]" type strings. PART_CACHE partnames; PART_CACHE partnames; typedef PART_CACHE::const_iterator PN_ITER; /// categories which we expect to find in the set of @a partnames /// categories which we expect to find in the set of @a partnames NAME_CACHE categories; NAME_CACHE categories; std::vector<char> readBuffer; ///< used by readSExpression() std::vector<char> readBuffer; ///< used by readString() /** /** * Function cache * Function cache Loading Loading @@ -109,10 +111,10 @@ class DIR_LIB_SOURCE : public LIB_SOURCE bool makePartName( STRING* aPartName, const char* aEntry, const STRING& aCategory ); bool makePartName( STRING* aPartName, const char* aEntry, const STRING& aCategory ); /** /** * Function readSExpression * Function readString * reads an s-expression into aResult. Candidate for virtual function later. * reads a Sweet string into aResult. Candidate for virtual function later. */ */ void readSExpression( STRING* aResult, const STRING& aNameSpec ) throw( IO_ERROR ); void readString( STRING* aResult, const STRING& aFileName ) throw( IO_ERROR ); /** /** * Function cacheOneDir * Function cacheOneDir Loading
new/sch_lib.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -90,7 +90,8 @@ protected: ///< derived classes must implement * Function ReadParts * Function ReadParts * fetches the s-expressions for each part given in @a aPartNames, into @a aResults, * fetches the s-expressions for each part given in @a aPartNames, into @a aResults, * honoring the array indices respectfully. * honoring the array indices respectfully. * @param aPartNames is a list of part names, one name per list element. * @param aPartNames is a list of part names, one name per list element. If a part name * 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( STRINGS* aResults, const STRINGS& aPartNames ) Loading