From: kawi Date: Thu, 1 Jan 2015 22:31:47 +0000 (+0100) Subject: ReDirStatistic works X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=4a48bcc17389a4279f5af54dca7f61885d495858;p=crepublib ReDirStatistic works --- diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp index e4d448d..e6a8821 100644 --- a/cunit/cuReTraverser.cpp +++ b/cunit/cuReTraverser.cpp @@ -47,6 +47,7 @@ private: 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"); + makeFile("dir2/2.x"); } void run(){ initTree(); @@ -85,10 +86,34 @@ private: ReDirStatistic stat; const ReStringList& list = stat.calculate(m_base.str(), 1); ReByteBuffer buffer; + ReByteBuffer expected; log(false, list.join("\n", buffer).str()); checkEqu(3u, list.count()); - checkEqu("", list.strOf(0)); - } + // "1 t:\temp\winfried\2\retestunit\dir1\n" + buffer.set(list.strOf(0), list.strLengthOf(0)); + checkT(buffer.startsWith("1\t")); + expected.set(m_base.str(), m_base.length()).append("dir1", -1); + // .append(ReTraverser::m_separatorStr, -1) + checkT(buffer.endsWith(expected.str())); + + buffer.setLength(0); + const ReStringList& list2 = stat.calculate(m_base.str(), 1, formatWithSizeFilesAndDirs); + log(false, list2.join("\n", buffer).str()); + + buffer.set(list.strOf(0), list.strLengthOf(0)); + checkT(buffer.startsWith(" 0.000116 MB 2 3\t")); + expected.set(m_base.str(), m_base.length()).append("dir1", -1); + checkT(buffer.endsWith(expected.str())); + + buffer.set(list.strOf(1), list.strLengthOf(1)); + checkT(buffer.startsWith(" 0.000039 MB 1 0\t")); + expected.set(m_base.str(), m_base.length()).append("dir2", -1); + checkT(buffer.endsWith(expected.str())); + + buffer.set(list.strOf(2), list.strLengthOf(2)); + checkT(buffer.startsWith(" 0.000191 MB 4 5\t")); + expected.set(m_base.str(), m_base.length()); + } }; extern void testReTraverser(void); diff --git a/os/DirTools.hpp b/os/DirTools.hpp index 9504115..f714b94 100644 --- a/os/DirTools.hpp +++ b/os/DirTools.hpp @@ -26,6 +26,9 @@ public: class ReDirStatistic; extern void formatLikeDu(const ReDirStatisticData& data, ReDirStatistic& parent, ReByteBuffer& line); +extern void formatWithSizeFilesAndDirs(const ReDirStatisticData& data, + ReDirStatistic& parent, ReByteBuffer& line); + /** * Calculates a statistic of a directory tree. */ diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index cab4336..de84c42 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -93,6 +93,7 @@ const ReStringList& ReDirStatistic::calculate(const char* base, int level, level = 1024; else if (level < 0) level = 0; + m_list.clear(); ReDirStatisticData** dataStack = new ReDirStatisticData*[level + 1]; memset(dataStack, 0, sizeof dataStack[0] * (level + 1)); dataStack[0] = new ReDirStatisticData(); @@ -103,17 +104,25 @@ const ReStringList& ReDirStatistic::calculate(const char* base, int level, current->m_path.set(base, -1); ReByteBuffer line; while( (entry = traverser.rawNextFile(currentDepth))){ - if (! entry->m_path.equals(current->m_path)){ + if (currentDepth <= level && ! entry->m_path.equals(current->m_path)){ if (currentDepth <= topOfStack){ - // close the entries of the stack above the new current: - while(topOfStack > currentDepth){ + // close the entries of the stack above the new top level: + while(topOfStack >= currentDepth){ // Add the data to the parent: - dataStack[topOfStack - 1]->add(*dataStack[topOfStack]); - // Append it to the result: - (*formatter)(*dataStack[topOfStack - 1], *this, line); + if (topOfStack > 0) + dataStack[topOfStack - 1]->add(*dataStack[topOfStack]); + // Append it to the result: + (*formatter)(*dataStack[topOfStack], *this, line); m_list.append(line); + topOfStack--; } - } else if (currentDepth < level){ + // We reuse the top of stack: + topOfStack++; + current = dataStack[topOfStack]; + // exchange the top of stack with the new found directory: + current->clear(); + current->m_path.set(entry->m_path.str(), entry->m_path.length());; + } else { // set up a new stack entry: if (currentDepth != topOfStack + 1) assert(currentDepth == topOfStack + 1); @@ -133,13 +142,18 @@ const ReStringList& ReDirStatistic::calculate(const char* base, int level, current->m_files++; } } + // close all dirs with parents: while(topOfStack > 0){ // Add the data to the parent: dataStack[topOfStack - 1]->add(*dataStack[topOfStack]); // Append it to the result: - (*formatter)(*dataStack[topOfStack - 1], *this, line); + (*formatter)(*dataStack[topOfStack], *this, line); m_list.append(line); + topOfStack--; } + // ... and the overall summery: + (*formatter)(*dataStack[0], *this, line); + m_list.append(line); // free the resources: for (int ix = 0; ix <= level; ix++) delete dataStack[ix]; @@ -161,5 +175,27 @@ const ReStringList& ReDirStatistic::calculate(const char* base, int level, void formatLikeDu(const ReDirStatisticData& data, ReDirStatistic& parent, ReByteBuffer& line){ line.setLength(0); - line.append(int(data.m_sizes / 1024)).append("\t").append(data.m_path); + // Round up to the next KiByte: + line.appendInt(int((data.m_sizes + 1023) / 1024)).append("\t").append(data.m_path); +} + +/** + * Formats a line in a standard way: MBytes, file count and directory count. + * + * This is a possible parameter of ReDirStatistic::calculate(). + * + * @param data statistic data, including path name + * @param parent the caller (ReDirStatistic). This allows to deliver + * a context to this formatting routine (through derivation of + * ReDirStatistic) + * @param line OUT: the formatted line, the conclusion of the statistic data + */ +void formatWithSizeFilesAndDirs(const ReDirStatisticData& data, + ReDirStatistic& parent, ReByteBuffer& line){ + line.setLength(0); + // Round up to the next KiByte: + char buffer[256]; + snprintf(buffer, sizeof buffer, "%14.6f MB %7d %7d\t", + data.m_sizes / 1E6, data.m_files, data.m_dirs); + line.append(buffer, -1).append(data.m_path); } diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index c870d9c..0ff17b3 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -25,7 +25,7 @@ const char* const ReTraverser::m_separatorStr = "\\"; #define isUndefHandle(handle) ((handle) == INVALID_HANDLE_VALUE) #define setHandleUndef(h) ((h) = INVALID_HANDLE_VALUE) #define findNextEntry(handle, data) (FindNextFileA(handle, data) != 0) -#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_dataBuffer) +#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_data) #endif ReDirStatus_t::ReDirStatus_t() : @@ -56,7 +56,7 @@ void ReDirStatus_t::freeEntry(){ } #elif defined __WIN32__ if (m_handle != INVALID_HANDLE_VALUE){ - CloseDir(m_handle); + FindClose(m_handle); m_handle = INVALID_HANDLE_VALUE; } #endif @@ -72,7 +72,7 @@ const char* ReDirStatus_t::node() const{ #ifdef __linux__ return m_data->d_name; #elif defined __WIN32__ - return m_data->cFileName; + return m_data.cFileName; #endif } /** @@ -85,8 +85,8 @@ bool ReDirStatus_t::isDotDir() const{ bool rc = m_data == NULL || (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')); + bool rc = m_data.cFileName[0] == '.' && (m_data.cFileName[1] == '\0' + || (m_data.cFileName[1] == '.' && m_data.cFileName[2] == '\0')); #endif return rc; } @@ -136,7 +136,7 @@ bool ReDirStatus_t::isDirectory() { #ifdef __linux__ return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_DIR) || S_ISDIR(getStatus()->st_mode); #elif defined __WIN32__ - return 0 != (m_dataBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); + return 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); #endif } /** @@ -151,7 +151,7 @@ bool ReDirStatus_t::isLink() { #ifdef __linux__ rc = (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_LNK) || S_ISLNK(getStatus()->st_mode); #elif defined __WIN32__ - rc = 0 != (m_dataBuffer.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT); + rc = 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT); #endif return rc; } @@ -164,7 +164,7 @@ bool ReDirStatus_t::isRegular() { #ifdef __linux__ return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_REG) || S_ISREG(getStatus()->st_mode); #elif defined __WIN32__ - return 0 != (m_dataBuffer.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); + return 0 != (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); #endif } /** @@ -176,7 +176,7 @@ FileSize_t ReDirStatus_t::fileSize() { #ifdef __linux__ return getStatus()->st_size; #elif defined __WIN32__ - return ((int64_t) m_dataBuffer.nFileSizeHigh << 32) + m_dataBuffer.nFileSizeLow; + return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow; #endif } /** @@ -188,7 +188,7 @@ const FileTime_t* ReDirStatus_t::modified() { #ifdef __linux__ return &(getStatus()->st_mtime); #elif defined __WIN32__ - return &m_dataBuffer.ftLastWriteTime; + return &m_data.ftLastWriteTime; #endif } @@ -361,7 +361,7 @@ ReDirStatus_t* ReTraverser::rawNextFile(int& level) } else { // this subdirectory is complete. We continue in the parent directory: current->freeEntry(); - if ( --m_level > 0){ + if ( --m_level >= 0){ again = true; } }