From: kawi Date: Tue, 30 Dec 2014 14:58:46 +0000 (+0100) Subject: ReTraverser implemented X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=d8bc9c4cd9b4e96d49083c6b447c9e6be94254f7;p=crepublib ReTraverser implemented --- diff --git a/base/ReHashList.cpp b/base/ReHashList.cpp index 178eae2..580e552 100644 --- a/base/ReHashList.cpp +++ b/base/ReHashList.cpp @@ -74,7 +74,7 @@ void ReHashList::put(const char* key, const char* value){ * @param value The value. */ void ReHashList::put(const ReByteBuffer& key, const ReByteBuffer& value){ - put(key.buffer(), key.length(), value.buffer(), value.length()); + put(key.str(), key.length(), value.str(), value.length()); } /** @brief Returns the value of a key value pair. * @@ -94,7 +94,7 @@ bool ReHashList::get(const Byte* key, size_t keyLength, if (rc){ ReSeqList::Sequence* seq = m_keys.getInfo(ix); // m_tag contains the index into m_values: - Byte* ptr = m_values.buffer() + seq->m_tag; + const Byte* ptr = m_values.str() + seq->m_tag; // m_values contains : size_t valLength = * (size_t*) ptr; ptr += sizeof (size_t); @@ -110,8 +110,8 @@ bool ReHashList::get(const Byte* key, size_t keyLength, * @return false: The key was not found. true: The key was found. */ bool ReHashList::get(const ReByteBuffer& key, - ReByteBuffer value) const{ - bool rc = get(key.buffer(), key.length(), value); + ReByteBuffer& value) const{ + bool rc = get(key.str(), key.length(), value); return rc; } /** @brief Deletes all entries in the list. @@ -141,7 +141,7 @@ bool ReHashList::next(size_t& position, ReByteBuffer* key, ReByteBuffer* value){ memcpy(key->buffer(), ptr, seq->m_length); } if (value != NULL){ - const Byte* ptr = m_values.buffer() + seq->m_tag; + const Byte* ptr = m_values.str() + seq->m_tag; size_t length = * (size_t*) ptr; ptr += sizeof (size_t); value->setLength(length); diff --git a/base/ReHashList.hpp b/base/ReHashList.hpp index 09f5e86..d91d79b 100644 --- a/base/ReHashList.hpp +++ b/base/ReHashList.hpp @@ -23,7 +23,7 @@ public: public: void clear(); bool get(const Byte* key, size_t keyLength, ReByteBuffer& value) const; - bool get(const ReByteBuffer& key, ReByteBuffer value) const; + bool get(const ReByteBuffer& key, ReByteBuffer& value) const; bool next(size_t& position, ReByteBuffer* key, ReByteBuffer* val); void put(const Byte* key, size_t keyLength, const Byte* value, size_t valueLength); void put(const char* key, const char* value); diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp index 1fecf21..6869162 100644 --- a/cunit/cuReTraverser.cpp +++ b/cunit/cuReTraverser.cpp @@ -11,16 +11,75 @@ class TestReTraverser : public ReTestUnit { public: TestReTraverser() : ReTestUnit("ReTraverser", __FILE__){ + createTestDir(); + m_base = getTestDir(); run(); } private: + ReByteBuffer m_base; +private: + void makeDir(const char* relPath){ + ReByteBuffer path(m_base); + path.append("/").append(relPath); + path.replaceAll("/", 1, ReTraverser::m_separatorStr, -1); + _mkdir(path.str()); + struct stat info; + if (stat(path.str(), &info) != 0){ + logF(true, "cannot create dir %1$s", path.str()); + } + } + void makeFile(const char* relPath){ + ReByteBuffer path(m_base); + path.append("/").append(relPath); + path.replaceAll("/", 1, ReTraverser::m_separatorStr, -1); + createFile(path.str(), path.str()); + struct stat info; + if (stat(path.str(), &info) != 0){ + logF(true, "cannot create file %1$s", path.str()); + } + } + void initTree(){ + makeFile("1.txt"); + makeDir("dir1"); + makeDir("dir2"); + makeDir("dir1/dir1_1"); + makeDir("dir1/dir1_2"); + makeDir("dir1/dir1_2/dir1_2_1"); + makeFile("dir1/dir1_2/dir1_2_1/x1.txt"); + makeFile("dir1/dir1_2/dir1_2_1/x2.txt"); + } void run(){ - testReplaceSubstring(); + initTree(); + testBasic(); } - void testReplaceSubstring(){ - ReTraverser traverser("/tmp/test"); + void checkOneFile(const char* node, const char* parent, const ReHashList& hash){ + ReByteBuffer path, expected; + checkT(hash.get(ReByteBuffer(node), path)); + expected.set(parent, -1); + if (! expected.endsWith(ReTraverser::m_separatorStr)) + expected.append(ReTraverser::m_separatorStr); + if (! path.endsWith(expected.str(), -1)) + checkT(false); + } + void testBasic(){ + ReTraverser traverser(m_base.str()); int level = 0; - const DirStatus_t* entry = traverser.nextFile(level); + DirStatus_t* entry; + ReHashList hash; + while( (entry = traverser.rawNextFile(level)) != NULL){ + hash.put(ReByteBuffer(entry->node(), -1), entry->m_path); + logF(false, "%d: %-12s %2d %s", + level, entry->node(), + int(entry->fileSize()), + entry->m_path.str()); + } + checkOneFile("x1.txt", "dir1_2_1", hash); + checkOneFile("x2.txt", "dir1_2_1", hash); + checkOneFile("dir1_2_1", "dir1_2", hash); + checkOneFile("dir1_1", "dir1", hash); + checkOneFile("dir1_2", "dir1", hash); + checkOneFile("dir1", m_base.str(), hash); + //checkEqu("xy12.ab", nameOfEntry(entry)); } }; diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index 098860e..052d38c 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -37,13 +37,24 @@ HANDLE findFirstEntry(const char* path, DirInfoStruct_t* data){ #define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_dataBuffer) #endif -const char* DirStatus_t::nameOfEntry() const{ +const char* DirStatus_t::node() const{ #ifdef __linux__ return m_data->d_name; #elif defined __WIN32__ return m_data->cFileName; #endif } +bool DirStatus_t::isDotDir() const{ +#ifdef __linux__ + bool rc = m_data->d_name[0] == '.' && (m_data->d_name[1] == '\0' + || (m_data->d_name[1] == '.' && m_data->d_name[2] == '\0')); +#elif defined __WIN32__ + bool rc = m_data->cFileName[0] == '.' && (m_data->cFileName[1] == '\0' + || (m_data->cFileName[1] == '.' && m_data->cFileName[2] == '\0')); +#endif + return rc; +} + bool DirStatus_t::isDirectory() { #ifdef __linux__ return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_DIR) || S_ISDIR(getStatus()->st_mode); @@ -144,7 +155,7 @@ bool DirEntryFilter_t::match(DirStatus_t& entry){ break; if (m_maxAge != 0 && DirStatus_t::filetimeToTime(entry.modified()) > m_maxAge) break; - if (m_nodePatterns != NULL && ! m_nodePatterns->match(entry.nameOfEntry())) + if (m_nodePatterns != NULL && ! m_nodePatterns->match(entry.node())) break; if (m_pathPatterns != NULL && ! m_pathPatterns->match(entry.m_path.str())) break; @@ -174,9 +185,10 @@ struct stat* DirStatus_t::getStatus() { */ ReTraverser::ReTraverser(const char* base) : m_level(-1), - m_base(base) + m_base(base), + // m_dirs + m_passNoForDirSearch(2) { - initEntry(base, 0); } /** @@ -198,16 +210,22 @@ ReTraverser::~ReTraverser() { DirStatus_t* ReTraverser::rawNextFile(int& level) { DirStatus_t* rc = NULL; - bool again = false; + bool alreadyRead = false; + bool again; do{ + again = false; if (m_level < 0){ // first call: - initEntry(m_base.str(), 0); - if (! isUndefHandle(m_dirs[0].m_handle)) - rc = &m_dirs[0]; + if (initEntry(m_base.str(), NULL, 0)){ + if (1 != m_passNoForDirSearch) + rc = &m_dirs[0]; + else + again = alreadyRead = true; + } } else { - DirStatus_t* current = &m_dirs[level]; - if (findNextEntry(current->m_handle, current->m_data)){ + DirStatus_t* current = &m_dirs[m_level]; + if (alreadyRead || findNextEntry(current->m_handle, current->m_data)){ + alreadyRead = false; // a file or directory found: if (current->m_passNo != m_passNoForDirSearch){ // we search for any file: @@ -215,35 +233,32 @@ DirStatus_t* ReTraverser::rawNextFile(int& level) } else { // we are interested only in subdirectories: again = true; - if (rc->isDirectory()){ - // open a new level: - level++; - m_base.append(ReTraverser::m_separatorStr); - m_base.append(rc->nameOfEntry()); - initEntry(m_base.str(), level + 1); + if (! current->isDotDir() && current->isDirectory()){ + // open a new level + alreadyRead = initEntry(current->m_path, current->node() , m_level + 1); } } } else { // the current subdir does not have more files: if (current->m_passNo == 1){ // we start the second pass: - initEntry(m_base.str(), m_level); + alreadyRead = initEntry(current->m_path, NULL, -1); current->m_passNo = 2; - if (! isUndefHandle(m_dirs[0].m_handle)) - rc = &m_dirs[0]; - else - again = true; + again = true; } else { - // this subdirectory is complete. We go to the parent directory: + // this subdirectory is complete. We continue in the parent directory: closeDir(current->m_handle); setHandleUndef(current->m_handle); - if (--level > 0){ + if ( --m_level > 0){ again = true; } } } } + if (rc != NULL && rc->isDotDir()) + again = true; } while(again); + level = m_level; return rc; } /** @@ -272,19 +287,32 @@ DirStatus_t* ReTraverser::nextFile(int& level, DirEntryFilter_t* filter){ /** * Initializes an entry in the directory entry stack. * - * @param path the name of the directory belonging to the entry - * @param level the index of the entry in the stack + * @param parent the parent directory of the entry + * @param node the name of the directory belonging to the entry (without path) + * @param level the index of the entry in the stack.
+ * If < 0: m_levels and m_path will not be changed + * @return true: a new file is available
+ * false/code>: findFirstEntry() signals: no entry. */ -void ReTraverser::initEntry(const char* path, int level){ +bool ReTraverser::initEntry(const ReByteBuffer& parent, const char* node, int level){ + bool rc = false; if (level < MAX_ENTRY_STACK_DEPTH){ - DirStatus_t* current = &m_dirs[level]; + if (level >= 0) + m_level = level; + DirStatus_t* current = &m_dirs[m_level]; initEntryBuffer(current); - current->m_handle = findFirstEntry(path, current->m_data); - if (! isUndefHandle(current->m_handle)){ - current->m_path.set(path, -1); - } - m_level = level; + current->m_passNo = 1; + if (level >= 0){ + current->m_path.set(parent.str(), parent.length()); + if (! parent.endsWith(m_separatorStr)) + current->m_path.append(m_separatorStr); + if (node != NULL) + current->m_path.append(node).append(m_separatorStr); + } + current->m_handle = findFirstEntry(current->m_path.str(), current->m_data); + rc = ! isUndefHandle(current->m_handle); } + return rc; } /** diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp index 8ce31d8..0c928af 100644 --- a/os/ReTraverser.hpp +++ b/os/ReTraverser.hpp @@ -36,14 +36,16 @@ typedef WIN32_FIND_DATAA DirInfoStruct_t; #endif class DirStatus_t{ public: - const char* nameOfEntry() const; + const char* node() const; bool isDirectory(); bool isLink(); bool isRegular(); FileSize_t fileSize(); const FileTime_t* modified(); + bool isDotDir() const; public: ReByteBuffer m_path; + // a pointer to the data: DirInfoStruct_t* m_data; FindFileHandle_t m_handle; int m_passNo; @@ -85,7 +87,7 @@ public: DirStatus_t* rawNextFile(int& level); DirStatus_t* nextFile(int& level, DirEntryFilter_t* filter = NULL); protected: - void initEntry(const char* path, int level); + bool initEntry(const ReByteBuffer& parent, const char* node, int level); void freeEntry(int level); protected: