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();
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);
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.
*/
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();
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);
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];
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 <code>ReDirStatistic::calculate()</code>.
+ *
+ * @param data statistic data, including path name
+ * @param parent the caller (<code>ReDirStatistic</code>). This allows to deliver
+ * a context to this formatting routine (through derivation of
+ * <code>ReDirStatistic</code>)
+ * @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);
}
#define isUndefHandle(handle) ((handle) == INVALID_HANDLE_VALUE)\r
#define setHandleUndef(h) ((h) = INVALID_HANDLE_VALUE)\r
#define findNextEntry(handle, data) (FindNextFileA(handle, data) != 0)\r
-#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_dataBuffer)\r
+#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_data)\r
#endif\r
\r
ReDirStatus_t::ReDirStatus_t() :\r
}\r
#elif defined __WIN32__\r
if (m_handle != INVALID_HANDLE_VALUE){\r
- CloseDir(m_handle);\r
+ FindClose(m_handle);\r
m_handle = INVALID_HANDLE_VALUE;\r
}\r
#endif\r
#ifdef __linux__\r
return m_data->d_name;\r
#elif defined __WIN32__\r
- return m_data->cFileName;\r
+ return m_data.cFileName;\r
#endif\r
}\r
/**\r
bool rc = m_data == NULL || (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
+ 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
#ifdef __linux__\r
return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_DIR) || S_ISDIR(getStatus()->st_mode);\r
#elif defined __WIN32__\r
- return 0 != (m_dataBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
+ return 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
#endif\r
}\r
/**\r
#ifdef __linux__\r
rc = (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_LNK) || S_ISLNK(getStatus()->st_mode);\r
#elif defined __WIN32__\r
- rc = 0 != (m_dataBuffer.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT);\r
+ rc = 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT);\r
#endif\r
return rc;\r
}\r
#ifdef __linux__\r
return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_REG) || S_ISREG(getStatus()->st_mode);\r
#elif defined __WIN32__\r
- return 0 != (m_dataBuffer.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));\r
+ return 0 != (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));\r
#endif\r
}\r
/**\r
#ifdef __linux__\r
return getStatus()->st_size;\r
#elif defined __WIN32__\r
- return ((int64_t) m_dataBuffer.nFileSizeHigh << 32) + m_dataBuffer.nFileSizeLow;\r
+ return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow;\r
#endif\r
}\r
/**\r
#ifdef __linux__\r
return &(getStatus()->st_mtime);\r
#elif defined __WIN32__\r
- return &m_dataBuffer.ftLastWriteTime;\r
+ return &m_data.ftLastWriteTime;\r
#endif\r
}\r
\r
} else {\r
// this subdirectory is complete. We continue in the parent directory:\r
current->freeEntry();\r
- if ( --m_level > 0){\r
+ if ( --m_level >= 0){\r
again = true;\r
}\r
}\r