* @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.
*
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 <length><sequence>:
size_t valLength = * (size_t*) ptr;
ptr += sizeof (size_t);
* @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.
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);
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);
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));
}
};
#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_dataBuffer)\r
#endif\r
\r
-const char* DirStatus_t::nameOfEntry() const{\r
+const char* DirStatus_t::node() const{\r
#ifdef __linux__\r
return m_data->d_name;\r
#elif defined __WIN32__\r
return m_data->cFileName;\r
#endif\r
}\r
+bool DirStatus_t::isDotDir() const{\r
+#ifdef __linux__\r
+ bool rc = m_data->d_name[0] == '.' && (m_data->d_name[1] == '\0' \r
+ || (m_data->d_name[1] == '.' && m_data->d_name[2] == '\0'));\r
+#elif defined __WIN32__\r
+ bool rc = m_data->cFileName[0] == '.' && (m_data->cFileName[1] == '\0' \r
+ || (m_data->cFileName[1] == '.' && m_data->cFileName[2] == '\0'));\r
+#endif\r
+ return rc;\r
+}\r
+\r
bool DirStatus_t::isDirectory() {\r
#ifdef __linux__\r
return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_DIR) || S_ISDIR(getStatus()->st_mode);\r
break;\r
if (m_maxAge != 0 && DirStatus_t::filetimeToTime(entry.modified()) > m_maxAge)\r
break;\r
- if (m_nodePatterns != NULL && ! m_nodePatterns->match(entry.nameOfEntry()))\r
+ if (m_nodePatterns != NULL && ! m_nodePatterns->match(entry.node()))\r
break;\r
if (m_pathPatterns != NULL && ! m_pathPatterns->match(entry.m_path.str()))\r
break;\r
*/\r
ReTraverser::ReTraverser(const char* base) :\r
m_level(-1),\r
- m_base(base)\r
+ m_base(base),\r
+ // m_dirs\r
+ m_passNoForDirSearch(2)\r
{\r
- initEntry(base, 0);\r
}\r
\r
/**\r
DirStatus_t* ReTraverser::rawNextFile(int& level)\r
{\r
DirStatus_t* rc = NULL;\r
- bool again = false;\r
+ bool alreadyRead = false;\r
+ bool again;\r
do{\r
+ again = false;\r
if (m_level < 0){\r
// first call:\r
- initEntry(m_base.str(), 0);\r
- if (! isUndefHandle(m_dirs[0].m_handle))\r
- rc = &m_dirs[0];\r
+ if (initEntry(m_base.str(), NULL, 0)){\r
+ if (1 != m_passNoForDirSearch)\r
+ rc = &m_dirs[0];\r
+ else\r
+ again = alreadyRead = true;\r
+ }\r
} else {\r
- DirStatus_t* current = &m_dirs[level];\r
- if (findNextEntry(current->m_handle, current->m_data)){\r
+ DirStatus_t* current = &m_dirs[m_level];\r
+ if (alreadyRead || findNextEntry(current->m_handle, current->m_data)){\r
+ alreadyRead = false;\r
// a file or directory found:\r
if (current->m_passNo != m_passNoForDirSearch){\r
// we search for any file:\r
} else {\r
// we are interested only in subdirectories:\r
again = true;\r
- if (rc->isDirectory()){\r
- // open a new level:\r
- level++;\r
- m_base.append(ReTraverser::m_separatorStr);\r
- m_base.append(rc->nameOfEntry());\r
- initEntry(m_base.str(), level + 1);\r
+ if (! current->isDotDir() && current->isDirectory()){\r
+ // open a new level\r
+ alreadyRead = initEntry(current->m_path, current->node() , m_level + 1);\r
}\r
}\r
} else {\r
// the current subdir does not have more files:\r
if (current->m_passNo == 1){\r
// we start the second pass:\r
- initEntry(m_base.str(), m_level);\r
+ alreadyRead = initEntry(current->m_path, NULL, -1);\r
current->m_passNo = 2;\r
- if (! isUndefHandle(m_dirs[0].m_handle))\r
- rc = &m_dirs[0];\r
- else\r
- again = true;\r
+ again = true;\r
} else {\r
- // this subdirectory is complete. We go to the parent directory:\r
+ // this subdirectory is complete. We continue in the parent directory:\r
closeDir(current->m_handle);\r
setHandleUndef(current->m_handle);\r
- if (--level > 0){\r
+ if ( --m_level > 0){\r
again = true;\r
}\r
}\r
}\r
}\r
+ if (rc != NULL && rc->isDotDir())\r
+ again = true;\r
} while(again);\r
+ level = m_level;\r
return rc;\r
}\r
/**\r
/**\r
* Initializes an entry in the directory entry stack.\r
*\r
- * @param path the name of the directory belonging to the entry\r
- * @param level the index of the entry in the stack\r
+ * @param parent the parent directory of the entry\r
+ * @param node the name of the directory belonging to the entry (without path)\r
+ * @param level the index of the entry in the stack.<br>\r
+ * If < 0: m_levels and m_path will not be changed\r
+ * @return <code>true</code>: a new file is available<br>\r
+ * <cude>false/code>: findFirstEntry() signals: no entry.\r
*/\r
-void ReTraverser::initEntry(const char* path, int level){\r
+bool ReTraverser::initEntry(const ReByteBuffer& parent, const char* node, int level){\r
+ bool rc = false;\r
if (level < MAX_ENTRY_STACK_DEPTH){\r
- DirStatus_t* current = &m_dirs[level];\r
+ if (level >= 0)\r
+ m_level = level;\r
+ DirStatus_t* current = &m_dirs[m_level];\r
initEntryBuffer(current);\r
- current->m_handle = findFirstEntry(path, current->m_data);\r
- if (! isUndefHandle(current->m_handle)){\r
- current->m_path.set(path, -1);\r
- }\r
- m_level = level;\r
+ current->m_passNo = 1;\r
+ if (level >= 0){\r
+ current->m_path.set(parent.str(), parent.length());\r
+ if (! parent.endsWith(m_separatorStr))\r
+ current->m_path.append(m_separatorStr);\r
+ if (node != NULL)\r
+ current->m_path.append(node).append(m_separatorStr);\r
+ }\r
+ current->m_handle = findFirstEntry(current->m_path.str(), current->m_data);\r
+ rc = ! isUndefHandle(current->m_handle);\r
}\r
+ return rc;\r
}\r
\r
/**\r
#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;
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: