Loading CMakeLists.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -212,6 +212,7 @@ add_subdirectory(polygon) add_subdirectory(polygon/kbool/src) add_subdirectory(polygon/kbool/src) add_subdirectory(potrace) add_subdirectory(potrace) add_subdirectory(bitmap2component) add_subdirectory(bitmap2component) #add_subdirectory(new) ############# ############# # Resources # # Resources # Loading new/CMakeLists.txt +3 −2 Original line number Original line Diff line number Diff line Loading @@ -56,10 +56,11 @@ else(DOXYGEN_FOUND) endif() endif() include_directories( ${CMAKE_SOURCE_DIR} ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) add_executable( test_dir_lib_source sch_dir_lib_source.cpp ) add_executable( test_dir_lib_source sch_dir_lib_source.cpp ${PROJECT_SOURCE_DIR}/common/richio.cpp ) #add_executable( test_dir_lib_source EXCLUDE_FROM_ALL sch_dir_lib_source.cpp ) #add_executable( test_dir_lib_source EXCLUDE_FROM_ALL sch_dir_lib_source.cpp ) target_link_libraries( test_dir_lib_source ${wxWidgets_LIBRARIES} ) target_link_libraries( test_dir_lib_source ${wxWidgets_LIBRARIES} ) #target_link_libraries( test_dir_lib_source common ${wxWidgets_LIBRARIES} ) new/design.h +0 −15 Original line number Original line Diff line number Diff line Loading @@ -352,21 +352,6 @@ Show architecture here. */ */ typedef std::string STRING; typedef std::string STRING; /** * Type STRING_TOKS * documents a container which holds a sequence of s-expressions suitable for parsing * with DSNLEXER. This can either be a sequence of DSN_SYMBOLs or a sequence of * fully parenthesis delimited s-expressions. There are 2 types: <ol> * <li> R C R33 "quoted-name" J2 * <li> (part R ())(part C ()) * </ol> * Notice that in the 1st example, there are 5 tokens in sequence, and in the * 2nd example there are two top most s-expressions in sequence. So the counts * in these are 5 and 2 respectively. */ typedef std::dequeue<STRING> STRING_TOKS; typedef std::dequeue<STRING> STRINGS; typedef std::dequeue<STRING> STRINGS; //typedef std::vector<wxString> WSTRINGS; //typedef std::vector<wxString> WSTRINGS; Loading new/sch_dir_lib_source.cpp +221 −32 Original line number Original line Diff line number Diff line Loading @@ -34,8 +34,13 @@ http://www.softagalleria.net/dirent.php http://www.softagalleria.net/dirent.php wx has these but they are based on wxString which can be wchar_t based and wx should wx has these but they are based on wxString which can be wchar_t based and wx should not be introduced at a level this low. not be introduced at a level this low. Part files: have the general form partname.part[.revN...] Categories: are any subdirectories immediately below the sourceURI, one level only. Part names: [category/]partname[/revN...] */ */ #include <sch_dir_lib_source.h> #include <sch_dir_lib_source.h> using namespace SCH; using namespace SCH; Loading @@ -60,7 +65,7 @@ using namespace std; /** /** * Class DIR_WRAP * Class DIR_WRAP * provides a destructor which may be invoked if an exception is thrown. * provides a destructor which is invoked if an exception is thrown. */ */ class DIR_WRAP class DIR_WRAP { { Loading @@ -77,12 +82,13 @@ public: DIR* operator->() { return dir; } DIR* operator->() { return dir; } DIR* operator*() { return dir; } DIR* operator*() { return dir; } operator bool () { return dir!=0; } }; }; /** /** * Class FILE_WRAP * Class FILE_WRAP * provides a destructor which may be invoked if an exception is thrown. * provides a destructor which is invoked if an exception is thrown. */ */ class FILE_WRAP class FILE_WRAP { { Loading Loading @@ -119,24 +125,30 @@ static const char* strrstr( const char* haystack, const char* needle ) return ret; return ret; } } /** static const char* endsWithRev( const char* cp, const char* limit ) * Function endsWithRev { * returns a pointer to the final string segment: "revN..." or NULL if none. // find last instance of ".rev" * @param start is the beginning of string segment to test, the partname or cp = strrstr( cp, ".rev" ); * any middle portion of it. if( cp ) * @param tail is a pointer to the terminating nul. * @param separator is the separating byte, expected: '.' or '/', depending on context. */ static const char* endsWithRev( const char* start, const char* tail, char separator ) { { const char* rev = cp + 1; bool sawDigit = false; cp += sizeof( ".rev" )-1; while( isdigit( *cp ) ) ++cp; if( cp != limit ) // there is garbage after "revN.." while( isdigit(*--tail) && tail>start ) rev = 0; { sawDigit = true; } return rev; if( sawDigit && tail-3 >= start && tail[-3] == separator ) { tail -= 2; if( tail[0]=='r' && tail[1]=='e' && tail[2]=='v' ) { return tail; } } } return 0; return 0; Loading Loading @@ -168,7 +180,7 @@ bool DIR_LIB_SOURCE::makePartFileName( const char* aEntry, // if versioning, test for a trailing "revN.." type of string // if versioning, test for a trailing "revN.." type of string if( useVersioning ) if( useVersioning ) { { const char* rev = endsWithRev( cp + sizeof(".part") - 1, limit ); const char* rev = endsWithRev( cp + sizeof(".part") - 1, limit, '.' ); if( rev ) if( rev ) { { if( aCategory.size() ) if( aCategory.size() ) Loading @@ -193,10 +205,51 @@ static bool isCategoryName( const char* aName ) } } #define MAX_PART_FILE_SIZE (1*1024*1024) // sanity check void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) throw( IO_ERROR ) { FILE_WRAP fw = open( aFilename.c_str(), O_RDONLY ); DIR_LIB_SOURCE::DIR_LIB_SOURCE( const STRING& aDirectoryPath, bool doUseVersioning ) if( fw == -1 ) throw( IO_ERROR ) { STRING msg = aFilename; msg += " cannot be open()ed for reading"; throw IO_ERROR( msg.c_str() ); } struct stat fs; fstat( fw, &fs ); // sanity check on file size if( fs.st_size > (1*1024*1024) ) { STRING msg = aFilename; msg += " seems too big. ( > 1mbyte )"; throw IO_ERROR( msg.c_str() ); } // we reuse the same readBuffer, which is not thread safe, but the API // is not expected to be thread safe. readBuffer.resize( fs.st_size ); size_t count = read( fw, &readBuffer[0], fs.st_size ); if( count != (size_t) fs.st_size ) { STRING msg = aFilename; msg += " cannot be read"; throw IO_ERROR( msg.c_str() ); } // std::string chars are not gauranteed to be contiguous in // future implementations of C++, so this is why we did not read into // aResult directly. aResult->assign( &readBuffer[0], count ); } DIR_LIB_SOURCE::DIR_LIB_SOURCE( const STRING& aDirectoryPath, bool doUseVersioning ) throw( IO_ERROR ) : readBuffer( 512 ) { { useVersioning = doUseVersioning; useVersioning = doUseVersioning; sourceURI = aDirectoryPath; sourceURI = aDirectoryPath; Loading Loading @@ -225,19 +278,121 @@ DIR_LIB_SOURCE::~DIR_LIB_SOURCE() } } void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory ) throw( IO_ERROR ) { aResults->clear(); if( aCategory.size() ) { STRING lower = aCategory + "/"; STRING upper = aCategory + char( '/' + 1 ); DIR_CACHE::const_iterator limit = sweets.upper_bound( upper ); for( DIR_CACHE::const_iterator it = sweets.lower_bound( lower ); it!=limit; ++it ) { const char* start = it->first.c_str(); size_t len = it->first.size(); if( !endsWithRev( start, start+len, '/' ) ) aResults->push_back( it->first ); } } else { for( DIR_CACHE::const_iterator it = sweets.begin(); it!=sweets.end(); ++it ) { const char* start = it->first.c_str(); size_t len = it->first.size(); if( !endsWithRev( start, start+len, '/' ) ) aResults->push_back( it->first ); } } } void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev ) throw( IO_ERROR ) { STRING partname = aPartName; if( aRev.size() ) partname += "/" + aRev; DIR_CACHE::iterator it = sweets.find( partname ); if( it == sweets.end() ) // part not found { partname += " not found."; throw IO_ERROR( partname.c_str() ); } if( !it->second ) // if the sweet string is not loaded yet { STRING filename = sourceURI + "/" + aPartName + ".part"; if( aRev.size() ) { filename += "." + aRev; } it->second = new STRING(); readSExpression( it->second, filename ); } *aResult = *it->second; } void DIR_LIB_SOURCE::ReadParts( STRINGS* aResults, const STRINGS& aPartNames ) throw( IO_ERROR ) { aResults->clear(); for( STRINGS::const_iterator n = aPartNames.begin(); n!=aPartNames.end(); ++n ) { aResults->push_back( STRING() ); ReadPart( &aResults->back(), *n ); } } void DIR_LIB_SOURCE::GetCategories( STRINGS* aResults ) throw( IO_ERROR ) { *aResults = categories; } #if defined(DEBUG) #include <richio.h> void DIR_LIB_SOURCE::Show() void DIR_LIB_SOURCE::Show() { { printf( "categories:\n" ); printf( "Show categories:\n" ); for( STRINGS::const_iterator it = categories.begin(); it!=categories.end(); ++it ) for( STRINGS::const_iterator it = categories.begin(); it!=categories.end(); ++it ) printf( " '%s'\n", it->c_str() ); printf( " '%s'\n", it->c_str() ); printf( "\n" ); printf( "\n" ); printf( "parts:\n" ); printf( "Show parts:\n" ); for( DIR_CACHE::const_iterator it = sweets.begin(); it != sweets.end(); ++it ) for( DIR_CACHE::const_iterator it = sweets.begin(); it != sweets.end(); ++it ) { { printf( " '%s'\n", it->first.c_str() ); printf( " '%s'\n", it->first.c_str() ); if( it->second ) { STRING_LINE_READER slr( *it->second, wxString( wxConvertMB2WX( it->first.c_str() ) ) ); while( slr.ReadLine() ) { printf( " %s", (char*) slr ); } printf( "\n" ); } } } } } #endif void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) Loading @@ -249,7 +404,7 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) DIR_WRAP dir = opendir( curDir.c_str() ); DIR_WRAP dir = opendir( curDir.c_str() ); if( !*dir ) if( !dir ) { { STRING msg = strerror( errno ); STRING msg = strerror( errno ); msg += "; scanning directory " + curDir; msg += "; scanning directory " + curDir; Loading @@ -257,10 +412,8 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) } } struct stat fs; struct stat fs; STRING partName; STRING partName; STRING fileName; STRING fileName; dirent* entry; dirent* entry; while( (entry = readdir( *dir )) != NULL ) while( (entry = readdir( *dir )) != NULL ) Loading @@ -270,8 +423,6 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) fileName = curDir + "/" + entry->d_name; fileName = curDir + "/" + entry->d_name; //D( printf("name: '%s'\n", fileName.c_str() );) if( !stat( fileName.c_str(), &fs ) ) if( !stat( fileName.c_str(), &fs ) ) { { if( S_ISREG( fs.st_mode ) && makePartFileName( entry->d_name, aCategory, &partName ) ) if( S_ISREG( fs.st_mode ) && makePartFileName( entry->d_name, aCategory, &partName ) ) Loading @@ -286,15 +437,16 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) */ */ sweets[partName] = NULL; // NULL for now, load the sweet later. sweets[partName] = NULL; // NULL for now, load the sweet later. //D( printf("part: %s\n", partName.c_str() );) } } else if( S_ISDIR( fs.st_mode ) && !aCategory.size() && isCategoryName( entry->d_name ) ) else if( S_ISDIR( fs.st_mode ) && !aCategory.size() && isCategoryName( entry->d_name ) ) { { // only one level of recursion is used, controlled by the // only one level of recursion is used, controlled by the // emptiness of aCategory. // emptiness of aCategory. //D( printf("category: %s\n", entry->d_name );) categories.push_back( entry->d_name ); categories.push_back( entry->d_name ); // somebody needs to test Windows (mingw), make sure it can // handle opendir() recursively doOneDir( entry->d_name ); doOneDir( entry->d_name ); } } else else Loading @@ -306,15 +458,53 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) } } #if 1 || defined( TEST_DIR_LIB_SOURCE ) #if (1 || defined( TEST_DIR_LIB_SOURCE )) && defined(DEBUG) int main( int argc, char** argv ) int main( int argc, char** argv ) { { STRINGS partnames; STRINGS sweets; try try { { DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", true ); DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", true ); // initially, only the DIR_CACHE sweets and STRING categories are loaded: uut.Show(); uut.Show(); uut.GetCategoricalPartNames( &partnames, "Category" ); printf( "GetCategoricalPartNames(Category):\n" ); for( STRINGS::const_iterator it = partnames.begin(); it!=partnames.end(); ++it ) { printf( " '%s'\n", it->c_str() ); } uut.ReadParts( &sweets, partnames ); // fetch the part names for ALL categories. uut.GetCategoricalPartNames( &partnames ); printf( "GetCategoricalPartNames(ALL):\n" ); for( STRINGS::const_iterator it = partnames.begin(); it!=partnames.end(); ++it ) { printf( " '%s'\n", it->c_str() ); } uut.ReadParts( &sweets, partnames ); printf( "Sweets for ALL parts:\n" ); STRINGS::const_iterator pn = partnames.begin(); for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) { printf( " %s: %s", pn->c_str(), it->c_str() ); } } catch( std::exception& ex ) { printf( "std::exception\n" ); } } catch( IO_ERROR ioe ) catch( IO_ERROR ioe ) Loading @@ -327,4 +517,3 @@ int main( int argc, char** argv ) #endif #endif new/sch_dir_lib_source.h +26 −19 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <sch_lib.h> #include <sch_lib.h> #include <map> #include <map> #include <vector> /** /** Loading @@ -54,8 +55,11 @@ class DIR_LIB_SOURCE : public LIB_SOURCE bool useVersioning; ///< use files with extension ".revNNN..", else not bool useVersioning; ///< use files with extension ".revNNN..", else not DIR_CACHE sweets; DIR_CACHE sweets; ///< @todo, don't really need to cache the sweets, only the partnames. STRINGS categories; STRINGS categories; std::vector<char> readBuffer; ///< used by readSExpression() /** /** * Function isPartFileName * Function isPartFileName Loading @@ -75,6 +79,13 @@ class DIR_LIB_SOURCE : public LIB_SOURCE bool makePartFileName( const char* aEntry, bool makePartFileName( const char* aEntry, const STRING& aCategory, STRING* aPartName ); const STRING& aCategory, STRING* aPartName ); /** * Function readSExpression * reads an s-expression into aResult. Candidate for virtual function later. */ void readSExpression( STRING* aResult, const STRING& aNameSpec ) throw( IO_ERROR ); /** /** * Function doOneDir * Function doOneDir * loads part names [and categories] from a directory given by * loads part names [and categories] from a directory given by Loading Loading @@ -109,39 +120,35 @@ public: //-----<LIB_SOURCE implementation functions >------------------------------ //-----<LIB_SOURCE implementation functions >------------------------------ void ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev=StrEmpty ) void ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev=StrEmpty ) throw( IO_ERROR ) throw( IO_ERROR ); { } void ReadParts( STRING_TOKS* aResults, const STRINGS& aPartNames ) void ReadParts( STRINGS* aResults, const STRINGS& aPartNames ) throw( IO_ERROR ) throw( IO_ERROR ); { } void GetCategories( STRING_TOKS* aResults ) throw( IO_ERROR ) void GetCategories( STRINGS* aResults ) throw( IO_ERROR ); { } void GetCategoricalPartNames( STRING_TOKS* aResults, void GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory=StrEmpty ) const STRING& aCategory=StrEmpty ) throw( IO_ERROR ) throw( IO_ERROR ); { } void GetRevisions( STRING_TOKS* aResults, const STRING& aPartName ) throw( IO_ERROR ) void GetRevisions( STRINGS* aResults, const STRING& aPartName ) throw( IO_ERROR ) { { // @todo } } void FindParts( STRING_TOKS* aResults, const STRING& aQuery ) throw( IO_ERROR ) void FindParts( STRINGS* aResults, const STRING& aQuery ) throw( IO_ERROR ) { { // @todo } } //-----</LIB_SOURCE implementation functions >------------------------------ //-----</LIB_SOURCE implementation functions >------------------------------ #if defined(DEBUG) /** /** * Function Show * Function Show * will output a debug dump of contents. * will output a debug dump of contents. */ */ void Show(); void Show(); #endif }; }; } // namespace SCH } // namespace SCH Loading Loading
CMakeLists.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -212,6 +212,7 @@ add_subdirectory(polygon) add_subdirectory(polygon/kbool/src) add_subdirectory(polygon/kbool/src) add_subdirectory(potrace) add_subdirectory(potrace) add_subdirectory(bitmap2component) add_subdirectory(bitmap2component) #add_subdirectory(new) ############# ############# # Resources # # Resources # Loading
new/CMakeLists.txt +3 −2 Original line number Original line Diff line number Diff line Loading @@ -56,10 +56,11 @@ else(DOXYGEN_FOUND) endif() endif() include_directories( ${CMAKE_SOURCE_DIR} ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) add_executable( test_dir_lib_source sch_dir_lib_source.cpp ) add_executable( test_dir_lib_source sch_dir_lib_source.cpp ${PROJECT_SOURCE_DIR}/common/richio.cpp ) #add_executable( test_dir_lib_source EXCLUDE_FROM_ALL sch_dir_lib_source.cpp ) #add_executable( test_dir_lib_source EXCLUDE_FROM_ALL sch_dir_lib_source.cpp ) target_link_libraries( test_dir_lib_source ${wxWidgets_LIBRARIES} ) target_link_libraries( test_dir_lib_source ${wxWidgets_LIBRARIES} ) #target_link_libraries( test_dir_lib_source common ${wxWidgets_LIBRARIES} )
new/design.h +0 −15 Original line number Original line Diff line number Diff line Loading @@ -352,21 +352,6 @@ Show architecture here. */ */ typedef std::string STRING; typedef std::string STRING; /** * Type STRING_TOKS * documents a container which holds a sequence of s-expressions suitable for parsing * with DSNLEXER. This can either be a sequence of DSN_SYMBOLs or a sequence of * fully parenthesis delimited s-expressions. There are 2 types: <ol> * <li> R C R33 "quoted-name" J2 * <li> (part R ())(part C ()) * </ol> * Notice that in the 1st example, there are 5 tokens in sequence, and in the * 2nd example there are two top most s-expressions in sequence. So the counts * in these are 5 and 2 respectively. */ typedef std::dequeue<STRING> STRING_TOKS; typedef std::dequeue<STRING> STRINGS; typedef std::dequeue<STRING> STRINGS; //typedef std::vector<wxString> WSTRINGS; //typedef std::vector<wxString> WSTRINGS; Loading
new/sch_dir_lib_source.cpp +221 −32 Original line number Original line Diff line number Diff line Loading @@ -34,8 +34,13 @@ http://www.softagalleria.net/dirent.php http://www.softagalleria.net/dirent.php wx has these but they are based on wxString which can be wchar_t based and wx should wx has these but they are based on wxString which can be wchar_t based and wx should not be introduced at a level this low. not be introduced at a level this low. Part files: have the general form partname.part[.revN...] Categories: are any subdirectories immediately below the sourceURI, one level only. Part names: [category/]partname[/revN...] */ */ #include <sch_dir_lib_source.h> #include <sch_dir_lib_source.h> using namespace SCH; using namespace SCH; Loading @@ -60,7 +65,7 @@ using namespace std; /** /** * Class DIR_WRAP * Class DIR_WRAP * provides a destructor which may be invoked if an exception is thrown. * provides a destructor which is invoked if an exception is thrown. */ */ class DIR_WRAP class DIR_WRAP { { Loading @@ -77,12 +82,13 @@ public: DIR* operator->() { return dir; } DIR* operator->() { return dir; } DIR* operator*() { return dir; } DIR* operator*() { return dir; } operator bool () { return dir!=0; } }; }; /** /** * Class FILE_WRAP * Class FILE_WRAP * provides a destructor which may be invoked if an exception is thrown. * provides a destructor which is invoked if an exception is thrown. */ */ class FILE_WRAP class FILE_WRAP { { Loading Loading @@ -119,24 +125,30 @@ static const char* strrstr( const char* haystack, const char* needle ) return ret; return ret; } } /** static const char* endsWithRev( const char* cp, const char* limit ) * Function endsWithRev { * returns a pointer to the final string segment: "revN..." or NULL if none. // find last instance of ".rev" * @param start is the beginning of string segment to test, the partname or cp = strrstr( cp, ".rev" ); * any middle portion of it. if( cp ) * @param tail is a pointer to the terminating nul. * @param separator is the separating byte, expected: '.' or '/', depending on context. */ static const char* endsWithRev( const char* start, const char* tail, char separator ) { { const char* rev = cp + 1; bool sawDigit = false; cp += sizeof( ".rev" )-1; while( isdigit( *cp ) ) ++cp; if( cp != limit ) // there is garbage after "revN.." while( isdigit(*--tail) && tail>start ) rev = 0; { sawDigit = true; } return rev; if( sawDigit && tail-3 >= start && tail[-3] == separator ) { tail -= 2; if( tail[0]=='r' && tail[1]=='e' && tail[2]=='v' ) { return tail; } } } return 0; return 0; Loading Loading @@ -168,7 +180,7 @@ bool DIR_LIB_SOURCE::makePartFileName( const char* aEntry, // if versioning, test for a trailing "revN.." type of string // if versioning, test for a trailing "revN.." type of string if( useVersioning ) if( useVersioning ) { { const char* rev = endsWithRev( cp + sizeof(".part") - 1, limit ); const char* rev = endsWithRev( cp + sizeof(".part") - 1, limit, '.' ); if( rev ) if( rev ) { { if( aCategory.size() ) if( aCategory.size() ) Loading @@ -193,10 +205,51 @@ static bool isCategoryName( const char* aName ) } } #define MAX_PART_FILE_SIZE (1*1024*1024) // sanity check void DIR_LIB_SOURCE::readSExpression( STRING* aResult, const STRING& aFilename ) throw( IO_ERROR ) { FILE_WRAP fw = open( aFilename.c_str(), O_RDONLY ); DIR_LIB_SOURCE::DIR_LIB_SOURCE( const STRING& aDirectoryPath, bool doUseVersioning ) if( fw == -1 ) throw( IO_ERROR ) { STRING msg = aFilename; msg += " cannot be open()ed for reading"; throw IO_ERROR( msg.c_str() ); } struct stat fs; fstat( fw, &fs ); // sanity check on file size if( fs.st_size > (1*1024*1024) ) { STRING msg = aFilename; msg += " seems too big. ( > 1mbyte )"; throw IO_ERROR( msg.c_str() ); } // we reuse the same readBuffer, which is not thread safe, but the API // is not expected to be thread safe. readBuffer.resize( fs.st_size ); size_t count = read( fw, &readBuffer[0], fs.st_size ); if( count != (size_t) fs.st_size ) { STRING msg = aFilename; msg += " cannot be read"; throw IO_ERROR( msg.c_str() ); } // std::string chars are not gauranteed to be contiguous in // future implementations of C++, so this is why we did not read into // aResult directly. aResult->assign( &readBuffer[0], count ); } DIR_LIB_SOURCE::DIR_LIB_SOURCE( const STRING& aDirectoryPath, bool doUseVersioning ) throw( IO_ERROR ) : readBuffer( 512 ) { { useVersioning = doUseVersioning; useVersioning = doUseVersioning; sourceURI = aDirectoryPath; sourceURI = aDirectoryPath; Loading Loading @@ -225,19 +278,121 @@ DIR_LIB_SOURCE::~DIR_LIB_SOURCE() } } void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory ) throw( IO_ERROR ) { aResults->clear(); if( aCategory.size() ) { STRING lower = aCategory + "/"; STRING upper = aCategory + char( '/' + 1 ); DIR_CACHE::const_iterator limit = sweets.upper_bound( upper ); for( DIR_CACHE::const_iterator it = sweets.lower_bound( lower ); it!=limit; ++it ) { const char* start = it->first.c_str(); size_t len = it->first.size(); if( !endsWithRev( start, start+len, '/' ) ) aResults->push_back( it->first ); } } else { for( DIR_CACHE::const_iterator it = sweets.begin(); it!=sweets.end(); ++it ) { const char* start = it->first.c_str(); size_t len = it->first.size(); if( !endsWithRev( start, start+len, '/' ) ) aResults->push_back( it->first ); } } } void DIR_LIB_SOURCE::ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev ) throw( IO_ERROR ) { STRING partname = aPartName; if( aRev.size() ) partname += "/" + aRev; DIR_CACHE::iterator it = sweets.find( partname ); if( it == sweets.end() ) // part not found { partname += " not found."; throw IO_ERROR( partname.c_str() ); } if( !it->second ) // if the sweet string is not loaded yet { STRING filename = sourceURI + "/" + aPartName + ".part"; if( aRev.size() ) { filename += "." + aRev; } it->second = new STRING(); readSExpression( it->second, filename ); } *aResult = *it->second; } void DIR_LIB_SOURCE::ReadParts( STRINGS* aResults, const STRINGS& aPartNames ) throw( IO_ERROR ) { aResults->clear(); for( STRINGS::const_iterator n = aPartNames.begin(); n!=aPartNames.end(); ++n ) { aResults->push_back( STRING() ); ReadPart( &aResults->back(), *n ); } } void DIR_LIB_SOURCE::GetCategories( STRINGS* aResults ) throw( IO_ERROR ) { *aResults = categories; } #if defined(DEBUG) #include <richio.h> void DIR_LIB_SOURCE::Show() void DIR_LIB_SOURCE::Show() { { printf( "categories:\n" ); printf( "Show categories:\n" ); for( STRINGS::const_iterator it = categories.begin(); it!=categories.end(); ++it ) for( STRINGS::const_iterator it = categories.begin(); it!=categories.end(); ++it ) printf( " '%s'\n", it->c_str() ); printf( " '%s'\n", it->c_str() ); printf( "\n" ); printf( "\n" ); printf( "parts:\n" ); printf( "Show parts:\n" ); for( DIR_CACHE::const_iterator it = sweets.begin(); it != sweets.end(); ++it ) for( DIR_CACHE::const_iterator it = sweets.begin(); it != sweets.end(); ++it ) { { printf( " '%s'\n", it->first.c_str() ); printf( " '%s'\n", it->first.c_str() ); if( it->second ) { STRING_LINE_READER slr( *it->second, wxString( wxConvertMB2WX( it->first.c_str() ) ) ); while( slr.ReadLine() ) { printf( " %s", (char*) slr ); } printf( "\n" ); } } } } } #endif void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) Loading @@ -249,7 +404,7 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) DIR_WRAP dir = opendir( curDir.c_str() ); DIR_WRAP dir = opendir( curDir.c_str() ); if( !*dir ) if( !dir ) { { STRING msg = strerror( errno ); STRING msg = strerror( errno ); msg += "; scanning directory " + curDir; msg += "; scanning directory " + curDir; Loading @@ -257,10 +412,8 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) } } struct stat fs; struct stat fs; STRING partName; STRING partName; STRING fileName; STRING fileName; dirent* entry; dirent* entry; while( (entry = readdir( *dir )) != NULL ) while( (entry = readdir( *dir )) != NULL ) Loading @@ -270,8 +423,6 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) fileName = curDir + "/" + entry->d_name; fileName = curDir + "/" + entry->d_name; //D( printf("name: '%s'\n", fileName.c_str() );) if( !stat( fileName.c_str(), &fs ) ) if( !stat( fileName.c_str(), &fs ) ) { { if( S_ISREG( fs.st_mode ) && makePartFileName( entry->d_name, aCategory, &partName ) ) if( S_ISREG( fs.st_mode ) && makePartFileName( entry->d_name, aCategory, &partName ) ) Loading @@ -286,15 +437,16 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) */ */ sweets[partName] = NULL; // NULL for now, load the sweet later. sweets[partName] = NULL; // NULL for now, load the sweet later. //D( printf("part: %s\n", partName.c_str() );) } } else if( S_ISDIR( fs.st_mode ) && !aCategory.size() && isCategoryName( entry->d_name ) ) else if( S_ISDIR( fs.st_mode ) && !aCategory.size() && isCategoryName( entry->d_name ) ) { { // only one level of recursion is used, controlled by the // only one level of recursion is used, controlled by the // emptiness of aCategory. // emptiness of aCategory. //D( printf("category: %s\n", entry->d_name );) categories.push_back( entry->d_name ); categories.push_back( entry->d_name ); // somebody needs to test Windows (mingw), make sure it can // handle opendir() recursively doOneDir( entry->d_name ); doOneDir( entry->d_name ); } } else else Loading @@ -306,15 +458,53 @@ void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR ) } } #if 1 || defined( TEST_DIR_LIB_SOURCE ) #if (1 || defined( TEST_DIR_LIB_SOURCE )) && defined(DEBUG) int main( int argc, char** argv ) int main( int argc, char** argv ) { { STRINGS partnames; STRINGS sweets; try try { { DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", true ); DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", true ); // initially, only the DIR_CACHE sweets and STRING categories are loaded: uut.Show(); uut.Show(); uut.GetCategoricalPartNames( &partnames, "Category" ); printf( "GetCategoricalPartNames(Category):\n" ); for( STRINGS::const_iterator it = partnames.begin(); it!=partnames.end(); ++it ) { printf( " '%s'\n", it->c_str() ); } uut.ReadParts( &sweets, partnames ); // fetch the part names for ALL categories. uut.GetCategoricalPartNames( &partnames ); printf( "GetCategoricalPartNames(ALL):\n" ); for( STRINGS::const_iterator it = partnames.begin(); it!=partnames.end(); ++it ) { printf( " '%s'\n", it->c_str() ); } uut.ReadParts( &sweets, partnames ); printf( "Sweets for ALL parts:\n" ); STRINGS::const_iterator pn = partnames.begin(); for( STRINGS::const_iterator it = sweets.begin(); it!=sweets.end(); ++it, ++pn ) { printf( " %s: %s", pn->c_str(), it->c_str() ); } } catch( std::exception& ex ) { printf( "std::exception\n" ); } } catch( IO_ERROR ioe ) catch( IO_ERROR ioe ) Loading @@ -327,4 +517,3 @@ int main( int argc, char** argv ) #endif #endif
new/sch_dir_lib_source.h +26 −19 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <sch_lib.h> #include <sch_lib.h> #include <map> #include <map> #include <vector> /** /** Loading @@ -54,8 +55,11 @@ class DIR_LIB_SOURCE : public LIB_SOURCE bool useVersioning; ///< use files with extension ".revNNN..", else not bool useVersioning; ///< use files with extension ".revNNN..", else not DIR_CACHE sweets; DIR_CACHE sweets; ///< @todo, don't really need to cache the sweets, only the partnames. STRINGS categories; STRINGS categories; std::vector<char> readBuffer; ///< used by readSExpression() /** /** * Function isPartFileName * Function isPartFileName Loading @@ -75,6 +79,13 @@ class DIR_LIB_SOURCE : public LIB_SOURCE bool makePartFileName( const char* aEntry, bool makePartFileName( const char* aEntry, const STRING& aCategory, STRING* aPartName ); const STRING& aCategory, STRING* aPartName ); /** * Function readSExpression * reads an s-expression into aResult. Candidate for virtual function later. */ void readSExpression( STRING* aResult, const STRING& aNameSpec ) throw( IO_ERROR ); /** /** * Function doOneDir * Function doOneDir * loads part names [and categories] from a directory given by * loads part names [and categories] from a directory given by Loading Loading @@ -109,39 +120,35 @@ public: //-----<LIB_SOURCE implementation functions >------------------------------ //-----<LIB_SOURCE implementation functions >------------------------------ void ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev=StrEmpty ) void ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev=StrEmpty ) throw( IO_ERROR ) throw( IO_ERROR ); { } void ReadParts( STRING_TOKS* aResults, const STRINGS& aPartNames ) void ReadParts( STRINGS* aResults, const STRINGS& aPartNames ) throw( IO_ERROR ) throw( IO_ERROR ); { } void GetCategories( STRING_TOKS* aResults ) throw( IO_ERROR ) void GetCategories( STRINGS* aResults ) throw( IO_ERROR ); { } void GetCategoricalPartNames( STRING_TOKS* aResults, void GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory=StrEmpty ) const STRING& aCategory=StrEmpty ) throw( IO_ERROR ) throw( IO_ERROR ); { } void GetRevisions( STRING_TOKS* aResults, const STRING& aPartName ) throw( IO_ERROR ) void GetRevisions( STRINGS* aResults, const STRING& aPartName ) throw( IO_ERROR ) { { // @todo } } void FindParts( STRING_TOKS* aResults, const STRING& aQuery ) throw( IO_ERROR ) void FindParts( STRINGS* aResults, const STRING& aQuery ) throw( IO_ERROR ) { { // @todo } } //-----</LIB_SOURCE implementation functions >------------------------------ //-----</LIB_SOURCE implementation functions >------------------------------ #if defined(DEBUG) /** /** * Function Show * Function Show * will output a debug dump of contents. * will output a debug dump of contents. */ */ void Show(); void Show(); #endif }; }; } // namespace SCH } // namespace SCH Loading