]> gitweb.hamatoma.de Git - crepublib/commitdiff
bugfixing (win)
authorHamatoma <git.tortouse@hm.f-r-e-i.de>
Wed, 4 Feb 2015 11:35:53 +0000 (12:35 +0100)
committerHamatoma <git.tortouse@hm.f-r-e-i.de>
Wed, 4 Feb 2015 11:35:53 +0000 (12:35 +0100)
12 files changed:
base/ReByteBuffer.cpp
base/ReCString.cpp
base/ReStringList.cpp
base/ReStringUtils.cpp
base/ReStringUtils.hpp
cunit/cuReDirTools.cpp [new file with mode: 0644]
cunit/cuReStringList.cpp
cunit/testall.cpp
os/ReDirTools.cpp
os/ReDirTools.hpp
os/ReTraverser.cpp
os/ReTraverser.hpp

index dde837e4bcfa911e2bf2fd1985539e589e85404c..724d7ef4f1d1f642f25598b1bf5f1343932be420 100644 (file)
@@ -239,7 +239,7 @@ ReByteBuffer& ReByteBuffer::appendHexDump(const char* data, size_t length,
                                append(" ", 1);
                }
                append("\n", 1);
-               length = length <= (int) bytesPerLine ? 0 : length - bytesPerLine;
+               length = length <= (size_t) bytesPerLine ? 0 : length - bytesPerLine;
                data += bytesPerLine;
                offset += bytesPerLine;
        }
index 1d10205ffc7dc7cd5a1f255cdfbc2cc98ebee30c..a81d72ab9058babf87d4bf25c640d2a668f991d0 100644 (file)
@@ -73,3 +73,4 @@ int _memicmp(const void* region1, const void* region2, int size)
     return rc;
 }
 #endif
+
index fab756a4c2bb8a2e7cc7b5633a002130d2e2444b..e09bd6d14e3e1c4850e86470b45add6278f0e2dd 100644 (file)
@@ -39,12 +39,11 @@ ReStringList& ReStringList::append(const char* source, Tag tagOf){
 /** @brief Appends a string at the end.
  *
  * @param source       the new string
- * @param tagOf        An item which will stored with the string. It can be retrieved
- *                                     by the same index.This class knows nothing about this
+ * @param tag          a number which will stored with the string. Not interpreted by the instance
  * @return                     the instance itself (for chaining)
  */
-ReStringList& ReStringList::append(const ReByteBuffer& source, Tag tagOf){
-       int ix = add(-1, source.str(), source.length() + 1, tagOf);
+ReStringList& ReStringList::append(const ReByteBuffer& source, Tag tag){
+       int ix = add(-1, source.str(), source.length() + 1, tag);
        return *this;
 }
 
@@ -126,9 +125,11 @@ void ReStringList::replace(Index index, const char* source, Tag tagOf){
  * @param source       the new string of the replaced element
  */
 void ReStringList::replaceString(Index index, const char* source){
+       Tag tag;
        if (index < count()){
                Sequence* seq = getInfo(index);
-               set(index, source, strlen(source) + 1, seq->m_tag);
+               getLengthAndTag(seq, tag);
+               set(index, source, -1, tag);
        }
 }
 /** @brief Replaces a tagOf in the internal array.
@@ -136,13 +137,12 @@ void ReStringList::replaceString(Index index, const char* source){
  * The string of the element remains unchanged.
  *
  * @param index        the element with this index will be replaced
- * @param source       the new string of the replaced element
+ * @param tag          the new tag
  */
-void ReStringList::replaceTag(Index index, Tag tagOf){
-       if (index < count()){
-               Sequence* seq = getInfo(index);
-               seq->m_tag = tagOf;
-       }
+void ReStringList::replaceTag(Index index, Tag tag){
+       ReByteBuffer buffer;
+       if (get(index, buffer))
+               set(index, buffer.str(), buffer.length(), tag);
 }
 
 /** @brief Returns the C string given by an index.
@@ -171,9 +171,9 @@ const char* ReStringList::strOf(Index index) const{
  */
 ReSeqArray::Tag ReStringList::tagOf(Index index) const{
        Tag rc = -1;
-       if (index < count()){
-               Sequence* seq = getInfo(index);
-               rc = seq->m_tag;
+       ReByteBuffer buffer;
+       if (! get(index, buffer, &rc)){
+               rc = -1;
        }
        return rc;
 }
@@ -189,7 +189,6 @@ size_t ReStringList::sizeOf(Index index) const{
        size_t rc = 0;
        if (index < count()){
                Sequence* seq = getInfo(index);
-        //@ToDo
                rc = getLength(seq);
        }
        return rc;
@@ -204,22 +203,21 @@ size_t ReStringList::sizeOf(Index index) const{
  */
 size_t ReStringList::strLengthOf(Index index) const{
        size_t rc = 0;
-       if (index < count()){
-               Sequence* seq = getInfo(index);
-                rc = rc = getLength(seq) - 1;
-       }
+       ReByteBuffer buffer;
+       if (get(index, buffer))
+               rc = buffer.length() - 1;
        return rc;
 }
 /** @brief Returns the sum of all string lengths stored in the array.
  *
- * @return the sum of all string lengths stored in the array
+ * @return the sum of all string lengths stored in the array (including trailing '\0')
  */
 size_t ReStringList::sumOfSizes() const{
        size_t rc = 0;
-
+       ReByteBuffer buffer;
        for (int ii = count() - 1; ii >= 0; ii--){
-               Sequence* seq = getInfo(ii);
-               rc += rc = getLength(seq);
+               get(ii, buffer);
+               rc += buffer.length();
        }
        return rc;
 }
index d24bb9481451a548b82f21caa462251374681c59..ba09ce777d2c676c4a41c70d2c27aee4a21c1fb5 100644 (file)
 
 const char ReStringUtils::AUTO_SEPARATOR = '\0';
 
-/** @brief Splits a filename into its parts.
- *
- * Example: file:/etc/samba/smb.conf
- * The 4 parts are:
- * <ul><li>A protocol: file:</li>
- * <li>The path. /etc/samba/ </li>
- * <li>The name: smb</li>
- * <li>The extension: .conf</li>
- * </ul>
- * All parts exclusive the name can be empty.
- *
- * <pre><code>Example:
- * ReByteBuffer protocol, path, name, ext;
- * ReByteBuffer fnBackup;
- * ReStringUtils::splitPath("/etc/sambe/smb.conf", &protocol, &path, &name, NULL);
- * ext.append(".bak");
- * ReStringUtils::joinPath(fnBackup, &protocol, &path, &name, &ext);
- * assert("/etc/sambe/smb.bak", fnBackup.getBuffer());
- * </code></pre>
+/** @brief Tests whether a phrase is in a phrase list.
  *
- * @param fullname                     The full name to split.
- * @param protocol                     Out: The protocol part of the filename. May be NULL.
- * @param path                         Out: The path of the filename. May be NULL.
- * @param name                         Out: The name part of the filename. May be NULL.
- * @param ext                          Out: The extension. May be NULL.
+ * @param phrase               The word to search.
+ * @param list                 The list to search. All phrases of the list are separated by <code>separator</code>.
+ * @param ignoreCase   true: The search is case insensitive. false: The search is case sensitive.
+ * @param separator            The separator in <code>list</code>. If <code>AUTO_SEPARATOR</code> the separator will
+ *                                             be taken from the list itself (the first character).
  */
-void ReStringUtils::splitPath(const char* fullname,
-       ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext){
-    const char currentSlash = strchr(fullname, '/') != NULL ? '/' : OS_SEPARATOR_CHAR;
-       const char* start = strchr(fullname, ':');
-       if (protocol != NULL){
-               protocol->setLength(0);
-               if (start != NULL)
-                       protocol->append(fullname, start - fullname + 1);
-       }
-       if (start == NULL)
-               start = fullname;
-       else
-               start++;
-
-       const char* end = strrchr(start, currentSlash);
-
-       if (path != 0){
-               path->setLength(0);
-               if (end != NULL)
-                       path->append(start, end - start + 1);
+bool ReStringUtils::isInList(const char* phrase, const char* list,
+               bool ignoreCase, char separator){
+       if (separator == AUTO_SEPARATOR)
+               separator = *list++;
+       const char* end = strchr(list, separator);
+       int phraseLength = strlen(phrase);
+       bool rc = false;
+       while(! rc && end != NULL){
+               if (end - list == phraseLength){
+                       if (ignoreCase)
+                               rc = strnicmp(list, phrase, phraseLength) == 0;
+                       else
+                               rc = strncmp(list, phrase, end - list) == 0;
+                       if (rc)
+                               break;
+               }
+               list = end + 1;
+               end = strchr(list, separator);
        }
-       if (end != NULL)
-               start = end + 1;
-       end = strrchr(start, '.');
-       if (name != NULL){
-               name->setLength(0);
-               if (end == NULL)
-                       name->append(start, strlen(start));
+       if (! rc){
+               if (ignoreCase)
+                       rc = strnicmp(list, phrase, end - list) == 0;
                else
-                       name->append(start, end - start);
-       }
-       if (ext != NULL){
-               ext->setLength(0);
-               if (end != NULL)
-                       ext->append(end, strlen(end));
+                       rc = strncmp(list, phrase, end - list) == 0;
        }
+       return rc;
 }
+
 /** Joins a filename from parts.
  *
  * <pre><code>Example:
@@ -138,6 +111,95 @@ ReByteBuffer& ReStringUtils::joinPath(ReByteBuffer& fullpath,
        return fullpath;
 }
 
+
+/**
+ * Returns the length of an integer in a given text.
+ *
+ * @param text         the number is expected in this text
+ * @param length       the length of the text. -1: <code>strlen(text)</code>
+ * @param value                OUT: the value of the integer. May be NULL
+ * @return                     the number of digits at the start of the text
+ */
+int ReStringUtils::lengthOfUnsigned(const char* text, int length, 
+       unsigned int* value){
+       int rc = 0;
+       unsigned int val = 0;
+       char cc;
+       if (length < 0)
+               // the '\0' is automatically a stopper, no need to call strlen()
+               length = INT_MAX;
+       while(rc < length && isdigit(cc = *text++)){
+               rc++;
+               val = 10*val + cc - '0'; 
+       }
+       if (value != NULL && rc != 0)
+               *value = val;
+       return rc;
+}
+
+/** @brief Splits a filename into its parts.
+ *
+ * Example: file:/etc/samba/smb.conf
+ * The 4 parts are:
+ * <ul><li>A protocol: file:</li>
+ * <li>The path. /etc/samba/ </li>
+ * <li>The name: smb</li>
+ * <li>The extension: .conf</li>
+ * </ul>
+ * All parts exclusive the name can be empty.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer protocol, path, name, ext;
+ * ReByteBuffer fnBackup;
+ * ReStringUtils::splitPath("/etc/sambe/smb.conf", &protocol, &path, &name, NULL);
+ * ext.append(".bak");
+ * ReStringUtils::joinPath(fnBackup, &protocol, &path, &name, &ext);
+ * assert("/etc/sambe/smb.bak", fnBackup.getBuffer());
+ * </code></pre>
+ *
+ * @param fullname                     The full name to split.
+ * @param protocol                     Out: The protocol part of the filename. May be NULL.
+ * @param path                         Out: The path of the filename. May be NULL.
+ * @param name                         Out: The name part of the filename. May be NULL.
+ * @param ext                          Out: The extension. May be NULL.
+ */
+void ReStringUtils::splitPath(const char* fullname,
+       ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext){
+    const char currentSlash = strchr(fullname, '/') != NULL ? '/' : OS_SEPARATOR_CHAR;
+       const char* start = strchr(fullname, ':');
+       if (protocol != NULL){
+               protocol->setLength(0);
+               if (start != NULL)
+                       protocol->append(fullname, start - fullname + 1);
+       }
+       if (start == NULL)
+               start = fullname;
+       else
+               start++;
+
+       const char* end = strrchr(start, currentSlash);
+
+       if (path != 0){
+               path->setLength(0);
+               if (end != NULL)
+                       path->append(start, end - start + 1);
+       }
+       if (end != NULL)
+               start = end + 1;
+       end = strrchr(start, '.');
+       if (name != NULL){
+               name->setLength(0);
+               if (end == NULL)
+                       name->append(start, strlen(start));
+               else
+                       name->append(start, end - start);
+       }
+       if (ext != NULL){
+               ext->setLength(0);
+               if (end != NULL)
+                       ext->append(end, strlen(end));
+       }
+}
 /** @brief Compares two strings case insensitive.
  *
  * @param string1              The first C string to compare.
@@ -158,39 +220,3 @@ int ReStringUtils::strnicmp(const char* string1, const char* string2, size_t len
        }
        return rc;
 }
-
-/** @brief Tests whether a phrase is in a phrase list.
- *
- * @param phrase               The word to search.
- * @param list                 The list to search. All phrases of the list are separated by <code>separator</code>.
- * @param ignoreCase   true: The search is case insensitive. false: The search is case sensitive.
- * @param separator            The separator in <code>list</code>. If <code>AUTO_SEPARATOR</code> the separator will
- *                                             be taken from the list itself (the first character).
- */
-bool ReStringUtils::isInList(const char* phrase, const char* list,
-               bool ignoreCase, char separator){
-       if (separator == AUTO_SEPARATOR)
-               separator = *list++;
-       const char* end = strchr(list, separator);
-       int phraseLength = strlen(phrase);
-       bool rc = false;
-       while(! rc && end != NULL){
-               if (end - list == phraseLength){
-                       if (ignoreCase)
-                               rc = strnicmp(list, phrase, phraseLength) == 0;
-                       else
-                               rc = strncmp(list, phrase, end - list) == 0;
-                       if (rc)
-                               break;
-               }
-               list = end + 1;
-               end = strchr(list, separator);
-       }
-       if (! rc){
-               if (ignoreCase)
-                       rc = strnicmp(list, phrase, end - list) == 0;
-               else
-                       rc = strncmp(list, phrase, end - list) == 0;
-       }
-       return rc;
-}
index 2c42f27c81f8fc86cd58af629c3bb2cb9ba3ec4e..2b29ff9b07349bcad1d3742341ebfbdefde44d33 100644 (file)
@@ -19,15 +19,16 @@ public:
        //@ If used in <code>isInList()</code> the first character of the list will be the separator.
        static const char AUTO_SEPARATOR;
 public:
-       static void splitPath(const char* fullname,
-               ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext);
+       static bool isInList(const char* phrase, const char* list,
+                       bool ignoreCase = true, char separator = AUTO_SEPARATOR);
        static ReByteBuffer& joinPath(ReByteBuffer& result,
                        ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext);
        static ReByteBuffer& joinPath(ReByteBuffer& result,
                        const char* protocol, const char* path, const char* name, const char* ext);
+       static int lengthOfUnsigned(const char* text, int length = -1, unsigned int* value = NULL);
+       static void splitPath(const char* fullname,
+               ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext);
        static int strnicmp(const char* string1, const char* string2, size_t length);
-       static bool isInList(const char* phrase, const char* list,
-                       bool ignoreCase = true, char separator = AUTO_SEPARATOR);
 };
 
 #endif /* RESTRINGUTILS_H_ */
diff --git a/cunit/cuReDirTools.cpp b/cunit/cuReDirTools.cpp
new file mode 100644 (file)
index 0000000..032ddd8
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * cuReTraverser.cpp
+ *
+ * License: Public domain
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * The latest sources: https://github.com/republib
+ */
+
+#include "base/rebase.hpp"
+#include "os/reos.hpp"
+
+static const char* s_empty[] = { NULL };
+
+class TestReDirTools : public ReTestUnit {
+public:
+       TestReDirTools() : ReTestUnit("ReTraverser", __FILE__){
+        m_base = testDir();
+        m_base.append("traverser").append(OS_SEPARATOR, -1);
+        _mkdir(m_base.str(), ALLPERMS);
+               run();
+       }
+private:
+    ReByteBuffer m_base;
+       ReByteBuffer m_buffer;
+private:
+    const char* makeDir(const char* relPath){
+        m_buffer = m_base;
+        m_buffer.append(relPath);
+        m_buffer.replaceAll("/", 1, OS_SEPARATOR, -1);
+        _mkdir(m_buffer.str(), ALLPERMS);
+        struct stat info;
+        if (stat(m_buffer.str(), &info) != 0){
+            logF(true, "cannot create dir %1$s", m_buffer.str());
+        }
+        return m_buffer.str();
+    }
+    void makeFile(const char* relPath){
+        ReByteBuffer path(m_base);
+        path.append("/").append(relPath);
+        path.replaceAll("/", 1, OS_SEPARATOR, -1);
+        createFile(path.str(), relPath);
+        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");
+               makeDir("dir1/cache");
+        makeFile("dir1/dir1_2/dir1_2_1/x1.txt");
+        makeFile("dir1/dir1_2/dir1_2_1/x2.txt");
+        makeFile("dir2/2.x");
+        makeFile("dir1/cache/cache.txt");
+    }
+       void run(){
+               initTree();
+
+               testToolSync();
+               testToolStatistic();
+               testBasic();
+               testDirOptions();
+               checkSetFilterFromProgramArgs();
+               testDirStatistic();
+        testCopyFile();
+        testList();
+       }
+    void testList(){
+        ReDirTools tools;
+        const char* argv[] = { "list", m_base.str(), NULL };
+        tools.list(2, argv);
+    }
+    void testCopyFile(){
+#if defined __linux__
+        ReByteBuffer src(m_base);
+        src.append("dir1/dir1_2/dir1_2_1/x1.txt");
+        ReByteBuffer trg(testDir());
+        trg.append("copy_x1.txt");
+        ReByteBuffer buffer;
+               buffer.ensureSize(5);
+        ReDirSync::copyFile(src.str(), NULL, trg.str(), buffer,
+                       ReLogger::globalLogger());
+        checkFileEqu(src.str(), trg.str());
+#else
+        log(false, "testCopyFile not implemented");
+#endif
+    }
+
+    void checkRelDate(time_t absTime, int relTime){
+        int diff = int(time(NULL) - relTime - absTime);
+        if (diff < 0)
+            diff = - diff;
+        checkT(diff < 2);
+    }
+
+    void testDirOptions(){
+        class MyOptions : public ReDirOptions{
+        public:
+            MyOptions() : ReDirOptions(s_empty, s_empty) {}
+        public:
+            int count() { return m_countCompoundUsage; }
+            const char** usage() { return m_compoundUsage; }
+        };
+        static const char* usage1[] = { "line1", "line2", NULL };
+        static const char* usage2[] = { "x1", "x2", "x3", NULL };
+        MyOptions opts;
+        opts.initCompoundUsage(sizeof usage1 + sizeof usage2);
+        opts.addCompoundUsage(usage1);
+        opts.addCompoundUsage(usage2);
+        checkEqu(7, opts.count());
+        checkEqu("line1", opts.usage()[0]);
+        checkEqu("line2", opts.usage()[1]);
+        checkEqu("x1", opts.usage()[2]);
+        checkEqu("x2", opts.usage()[3]);
+        checkEqu("x3", opts.usage()[4]);
+
+        // local time: +3600
+        const int DIFF = 3600;
+        checkEqu(24*60*60 - DIFF, (int) opts.checkDate("1970.01.02"));
+        checkEqu(24*60*60+3600-DIFF, (int) opts.checkDate("1970.01.02/1"));
+        checkEqu(24*60*60 + 2*3600 + 33*60 - DIFF, (int) opts.checkDate("1970.01.02/02:33"));
+        checkRelDate(opts.checkDate("3m"), 3*60);
+        checkRelDate(opts.checkDate("7h"), 7*60*60);
+        checkRelDate(opts.checkDate("5d"), 5*24*60*60);
+
+        checkEqu(125ll, opts.checkSize("125"));
+        checkEqu(125ll, opts.checkSize("125b"));
+        checkEqu(3000ll, opts.checkSize("3k"));
+        checkEqu(3*1024ll, opts.checkSize("3K"));
+        checkEqu(4*1000*1000ll, opts.checkSize("4m"));
+        checkEqu(4*1024*1024ll, opts.checkSize("4M"));
+        checkEqu(5*1000*1000*1000ll, opts.checkSize("5g"));
+        checkEqu(5*1024*1024*1024ll, opts.checkSize("5G"));
+
+    }
+    void checkSetFilterFromProgramArgs(){
+        ReDirOptions opts(s_empty, s_empty);
+        opts.addStandardFilterOptions();
+        const char* argv[] = { "x", "-y1970.01.02", "-o1970.01.03",
+            "-D5", "-d1", "-z1k", "-Z2M", "-p;*;-*~"
+        };
+        ReDirEntryFilter_t filter;
+        opts.programArgsChangeable().init(sizeof argv / sizeof argv[0], argv);
+        opts.setFilterFromProgramArgs(filter);
+        // local time: +3600
+        const int DIFF = 3600;
+        checkEqu(1*24*3600 - DIFF, (int) filter.m_maxAge);
+        checkEqu(2*24*3600 - DIFF, (int) filter.m_minAge);
+        checkEqu(5, (int) filter.m_maxDepth);
+        checkEqu(1, (int) filter.m_minDepth);
+        checkEqu(1000ll, filter.m_minSize);
+        checkEqu(2*1024*1024ll, filter.m_maxSize);
+        checkNN(filter.m_nodePatterns);
+        checkEqu(";*;-*~", filter.m_nodePatterns->patternString());
+    }
+    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(OS_SEPARATOR))
+            expected.append(OS_SEPARATOR);
+        if (! path.endsWith(expected.str(), -1))
+            checkT(false); 
+    }
+       void testBasic(){
+               ReTraverser traverser(m_base.str());
+               RePatternList patterns;
+               // exclude */cache/*
+               ReByteBuffer buffer(";*;-*/cache");
+               patterns.set(buffer.str());
+               traverser.setDirPattern(&patterns);
+               int level = 0;
+               ReDirStatus_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);
+               checkF(hash.get("cache.txt", buffer));
+       }
+       void testDirStatistic(){
+               ReDirStatistic stat;
+               const ReStringList& list = stat.calculate(m_base.str(), 1);
+               ReByteBuffer buffer;
+        ReByteBuffer expected;
+               log(false, list.join("\n", buffer).str());
+               checkEqu(4u, list.count());
+        // "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(OS_SEPARATOR);
+        // .append(OS_SEPARATOR, -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.000074 MB       3       4\t"));
+        expected.set(m_base.str(), m_base.length()).append("dir1", -1)
+             .append(OS_SEPARATOR);
+        checkT(buffer.endsWith(expected.str()));
+
+        buffer.set(list.strOf(1), list.strLengthOf(1));
+        checkT(buffer.startsWith("      0.000054 MB       2       3\t"));
+        expected.set(m_base.str(), m_base.length()).append("dir2", -1)
+             .append(OS_SEPARATOR);
+        checkT(buffer.endsWith(expected.str()));
+
+        buffer.set(list.strOf(2), list.strLengthOf(2));
+        checkT(buffer.startsWith("      0.000087 MB       5       6\t"));
+        expected.set(m_base.str(), m_base.length());
+    }
+       void testToolStatistic(){
+               ReDirTools tools;
+               const char* argv[] = { "dt", "stat", "-P;*;-*/cache/*", m_base.str(), "2" };
+               tools.main(5, (char**) argv);
+       }
+       void testToolSync(){
+               ReDirTools tools;
+               ReByteBuffer source(m_base);
+               source.append("dir1");
+               ReByteBuffer target(makeDir("synctest"));
+               const char* argv[] = { "dt", "sync", "-P;*;-*/cache/*", "-p;*.txt",
+                       source.str(), target.str() };
+               tools.main(6, (char**) argv);
+       }
+};
+extern void testReDirTools(void);
+
+void testReDirTools(void){
+       TestReDirTools unit;
+}
index 6b7266c78afe9af35ec1e694e7662bec393bafc6..1a58df58ddb031e9d256ede04e51d4673e7e0202 100644 (file)
@@ -26,9 +26,9 @@ private:
                ReStringList list;
                ReByteBuffer line;
                line.set("Hi", -1);
-        list.append(line, 99ll);
+        list.append(line, 99);
         line.append("!", -1);
-               list.append(line, -5ll);
+               list.append(line, -5);
                checkEqu(2u, list.count());
                checkEqu(99ll, list.tagOf(0));
                checkEqu("Hi", list.strOf(0));
index 2634bb6d9650c8cbf909034df051a3e1e0f74353..8960425720124b6e0f14a2e3e6f6010ff34b0590 100644 (file)
@@ -41,10 +41,8 @@ void testBase(){
 
 }
 void testString(){
-    void testReCString();
-       testReCString();
-       extern void testReStringList(void);
-       testReStringList();
+       void testReStringUtils(void);
+       testReStringUtils();
 
        extern void testReI18N(void);
        testReI18N();
@@ -58,8 +56,13 @@ void testString(){
        testReMatcher();
 }
 void testOs(){
+       void testReDirTools();
+       testReDirTools();
+
        void testReTraverser();
        testReTraverser();
+       void testReDirTools();
+       testReDirTools();
 }
 void testMath(){
        extern void testReMD5();
@@ -70,7 +73,7 @@ void testMath(){
 void testAll(){
        try
        {
-               testBase();
+               testString();
 
                testOs();
                testBase();
index 0805df4c86f44c9d1c701c3798b34a4a5e5d6c9c..7742d5cef996f40de86c2886a81f7887480626ec 100644 (file)
@@ -109,12 +109,14 @@ const char* s_syncExamples[] = {
  * @param example   a string vector with some examples how to use the command
  */
 ReDirOptions::ReDirOptions(const char* usage[], const char* examples[]) :
+       ReTraceUnit(INT_MAX, INT_MAX),
     m_programArgs(usage, examples),
     m_nodePatterns(),
     m_pathPatterns(),
     m_compoundUsage(NULL),
     m_countCompoundUsage(0),
-    m_output(stdout)
+    m_output(stdout),
+       m_verboseLevel(V_NORMAL)
 {
 }
 /**
@@ -147,7 +149,7 @@ void ReDirOptions::addCompoundUsage(const char** usage){
  * Adds the standard filter options.
  */
 void ReDirOptions::addStandardFilterOptions(){
-       // standard short options: D d O o P p q T t y Z z
+       // standard short options: D d O o P p T t v y Z z
     m_programArgs.addInt("maxdepth",
         i18n("the depth of the subdirectory is lower or equal <number>\n"
         "0: search is done only in the base directory"),
@@ -185,9 +187,9 @@ void ReDirOptions::addStandardFilterOptions(){
             "of the 'not patterns' matches\n"
             "examples: '*.cpp;*.hpp;Make*' '*;-*.bak;-*~"),
         'p', "basename-pattern", false, NULL);
-    m_programArgs.addBool("quiet",
-        i18n("no additional information like runtime"),
-        'q', "quiet", false);
+    m_programArgs.addString("verbose",
+        i18n("verbose level: 0: no info, 1: summary only, 2: normal, 3: chatter mode, 4: debug"),
+        'v', "verbose", false, "1");
     m_programArgs.addInt("trace",
         i18n("all <number> seconds the current path will be traced\n"
             "0: no trace"),
@@ -446,7 +448,15 @@ void ReDirOptions::checkStandardFilterOptions(){
     checkSize(m_programArgs.getString("maxsize", buffer));
     checkSize(m_programArgs.getString("minsize", buffer));
     checkPatternList(m_programArgs.getString("nodepattern", buffer));    
-    checkPatternList(m_programArgs.getString("pathpattern", buffer));    
+    checkPatternList(m_programArgs.getString("pathpattern", buffer));
+       if (m_programArgs.getString("verbose", buffer)[0] != '\0'){
+               unsigned level = V_NORMAL;
+               if (ReStringUtils::lengthOfUnsigned(buffer.str(), -1, &level)
+                               != buffer.length())
+                       help(i18n("verbose level is not a number (or '')"), buffer.str());
+               else
+                       m_verboseLevel = VerboseLevel(level);
+       }
 }
 
 /**
@@ -540,7 +550,8 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter_t& filter){
         m_pathPatterns.set(buffer.str());
         filter.m_pathPatterns = &m_pathPatterns;
     }
-    filter.m_traceInterval = m_programArgs.getInt("trace");
+    if ( (m_interval = m_programArgs.getInt("trace")) != 0)
+               m_triggerCount = 10;
        if (m_programArgs.getString("output", buffer)[0] != '\0'){
                if ( (m_output = fopen(buffer.str(), "w")) == NULL){
                        help("cannot open output file", buffer.str());
@@ -705,7 +716,7 @@ const ReStringList& ReDirStatistic::calculate(const char* base, int level,
                 time_t now = time(NULL);
                 int diff = int(now - m_lastTrace);
                 if (diff >= m_traceInterval){
-                    fprintf(stderr, "%s\n", current->m_path.str());
+                    fprintf(m_output, "%s\n", current->m_path.str());
                     m_lastTrace = now;
                 }
             }
@@ -914,7 +925,7 @@ void ReDirList::list(int argc, const char* argv[]){
 ReDirBatch::ReDirBatch() :
     ReDirOptions(s_batchUsage, s_batchExamples)
 {
-       // standard short options: D d O o P p q T t y Z z
+       // standard short options: D d O o P p T t v y Z z
     m_programArgs.addString("first",
         i18n("defines the first line of the output"),
         '1', "first-line", true,
@@ -1094,7 +1105,7 @@ ReDirSync::ReDirSync() :
     ReDirOptions(s_syncUsage, s_syncExamples),
     m_buffer()
 {
-       // standard short options: D d O o P p q T t y Z z
+       // standard short options: D d O o P p T t v y Z z
        m_buffer.ensureSize(4u*1024u*1024u);
     m_programArgs.addBool("add",
         i18n("copies only files which does not exist on the target"),
@@ -1109,9 +1120,6 @@ ReDirSync::ReDirSync() :
     m_programArgs.addBool("ignoredate",
                        i18n("the modification is recognized only by the different size (not time)"),
         'i', "ignore-time", false);
-    m_programArgs.addBool("chatter",
-                       i18n("comments the action of each file"),
-        'h', "chatter", false);
     m_programArgs.addBool("mustexist",
                        i18n("files which don't exist on the target will not be copied"),
         'm', "must-exist", false);
@@ -1342,12 +1350,10 @@ void ReDirSync::synchronize(int argc, const char* argv[]){
             help(i18n("target is not a directory: $1"), target.str());
         size_t lengthTargetBase = target.length();
         bool addOnly = m_programArgs.getBool("add");
-        bool chatterMode = m_programArgs.getBool("chatter");
                int maxFileTimeDiff = m_programArgs.getInt("timediff");
                bool dry = m_programArgs.getBool("dry");
                bool ignoreDate = m_programArgs.getBool("ignoredate");
         bool mustExist = m_programArgs.getBool("mustexist");
-        bool verbose = ! m_programArgs.getBool("quiet");
         setFilterFromProgramArgs(filter);
         int64_t sumSizes = 0;
         int files = 0;
@@ -1391,33 +1397,33 @@ void ReDirSync::synchronize(int argc, const char* argv[]){
                                const char* targetRelativePath = targetFile.str() + ixTargetRelative + 1;
                 bool exists = stat(targetFile.str(), &info) == 0;
                 if (! exists && mustExist){
-                                       if (chatterMode)
+                                       if (m_verboseLevel == V_CHATTER)
                                                fprintf(m_output, "-ignored: %s does not exist\n", targetRelativePath);
                                        continue;
                                }
                                if (exists){
                                        if (addOnly){
-                                               if (chatterMode)
+                                               if (m_verboseLevel >= V_CHATTER)
                                                        fprintf(m_output, "~ignored: %s exists\n", targetRelativePath);
                                                continue;
                                        }
                                        if (ignoreDate && entry->fileSize() == info.st_size){
-                                               if (chatterMode)
+                                               if (m_verboseLevel >= V_CHATTER)
                                                        fprintf(m_output, "_ignored: %s same size\n", targetRelativePath);
                                                continue;
                                        }
                                        // target younger than source?
-                                       int diff = info.st_mtime - entry->filetimeToTime(entry->modified());
+                                       int diff = int(info.st_mtime - entry->filetimeToTime(entry->modified()));
                                        if (! ignoreDate && info.st_mtime - entry->filetimeToTime(entry->modified())
                                                        <= maxFileTimeDiff) {
-                                               if (chatterMode)
+                                               if (m_verboseLevel >= V_CHATTER)
                                                        fprintf(m_output, "=ignored: %s same time\n", targetRelativePath);
                                                continue;
                                        }
                                }
                                files++;
                                sumSizes += entry->fileSize();
-                               if (verbose || chatterMode)
+                               if (m_verboseLevel >= V_NORMAL)
                                        fprintf(m_output, "%c%s%s\n", exists ? '!' : '+', targetRelativePath,
                                                dry ? " would be copied" : "");
                                if (! dry)
@@ -1427,7 +1433,7 @@ void ReDirSync::synchronize(int argc, const char* argv[]){
                        treeDirs += traverser.directories();
                        treeSumSizes+= traverser.sizes();
         }
-        if (verbose){
+        if (m_verboseLevel >= V_SUMMARY){
             int duration = int(time(NULL) - start);
             fprintf(m_output, i18n(
                                "=== copied:    %02d:%02d sec  %7d file(s) %12.6f MByte (%.3f MB/sec).\n"
index 266593eb5dbd048eee6034573ec1b6bad569d15c..d5053a1a1359b9876609e6913b05af25f93ec21e 100644 (file)
 #ifndef OS_DIRTOOLS_HPP_
 #define OS_DIRTOOLS_HPP_
 
-class ReDirOptions {
+class ReDirOptions : ReTraceUnit{
+public:
+       enum VerboseLevel {
+               V_UNDEF,
+               V_QUIET,
+               V_SUMMARY,
+               V_NORMAL,
+               V_CHATTER,
+               V_DEBUG
+       };
 public:
     ReDirOptions(const char* usage[], const char* example[]);
     ~ReDirOptions();
@@ -50,6 +59,7 @@ protected:
     const char** m_compoundUsage;
     int m_countCompoundUsage;
        FILE* m_output;
+       VerboseLevel m_verboseLevel;
 };
 
 #if defined __linux__
index d3620d78761101b9ff53f3c90552eb4f62d4237e..8d38ce8091ec7faa63dd3ba6d6954978bef6f6f0 100644 (file)
@@ -335,10 +335,7 @@ ReDirEntryFilter_t::ReDirEntryFilter_t() :
        m_minAge(0),\r
        m_maxAge(0),\r
     m_minDepth(0),\r
-    m_maxDepth(512),\r
-    m_traceInterval(0),\r
-    m_lastTrace(0),\r
-    m_traceCounter(0)\r
+    m_maxDepth(512)\r
 {\r
 }\r
 \r
@@ -353,13 +350,6 @@ ReDirEntryFilter_t::~ReDirEntryFilter_t(){
 bool ReDirEntryFilter_t::match(ReDirStatus_t& entry){\r
        bool rc = false;\r
        do {\r
-        if (m_traceCounter++ % 100 == 0 && m_traceInterval > 0){\r
-            time_t now = time(NULL);\r
-            if (int(now - m_lastTrace) > m_traceInterval){\r
-                m_lastTrace = now;\r
-                fprintf(stderr, "%s%s\n", entry.m_path.str(), entry.node());\r
-            }\r
-        }\r
                if (0 == (entry.type() & m_types))\r
                        break;\r
         int64_t size = entry.fileSize();\r
@@ -393,13 +383,45 @@ struct stat* ReDirStatus_t::getStatus() {
        return &m_status;\r
 }\r
 #endif\r
+
+/**
+* Constructor.
+*
+* @param triggerCount  efficiency: only every N calls a time check takes place
+* @param interval              the minimum number of seconds between two traces
+*/
+ReTraceUnit::ReTraceUnit(int triggerCount, int interval) :
+       m_count(0),
+       m_triggerCount(triggerCount),
+       m_lastTrace(time(NULL)),
+       m_interval(interval)
+{
+}
+/**
+ * Destructor.
+ */
+ReTraceUnit::~ReTraceUnit(){
+}
+\r
+/**\r
+ * Prints a message.\r
+ *\r
+ * Often overwritten by a subclass.\r
+ *\r
+ * @param message      message for the trace\r
+ * @return                     <code>true</code> (for chaining)\r
+ */\r
+bool ReTraceUnit::trace(const char* message){
+       printf("%d\n", message);
+       return true;
+}
 \r
 /**\r
  * Constructor.\r
  *\r
  * @param base         the base directory. The traversal starts at this point\r
  */\r
-ReTraverser::ReTraverser(const char* base) :\r
+ReTraverser::ReTraverser(const char* base, ReTraceUnit* tracer) :\r
     m_minLevel(0),\r
     m_maxLevel(512),\r
        m_level(-1),\r
@@ -409,8 +431,8 @@ ReTraverser::ReTraverser(const char* base) :
     m_dirPatterns(NULL),\r
        m_directories(0),\r
        m_files(0),\r
-       m_sizes(0ll)\r
-\r
+       m_sizes(0ll),\r
+       m_tracer(tracer)\r
 {\r
        memset(m_dirs, 0, sizeof m_dirs);\r
        m_dirs[0] = new ReDirStatus_t();\r
@@ -469,6 +491,9 @@ ReDirStatus_t* ReTraverser::rawNextFile(int& level)
                        if (alreadyRead || current->findNext()){\r
                                alreadyRead = false;\r
                                // a file or directory found:\r
+                               if (m_tracer != NULL && m_tracer->isCountTriggered() \r
+                                               && m_tracer->isTimeTriggered())\r
+                                       m_tracer->trace(current->fullName());\r
                                if (current->m_passNo != m_passNoForDirSearch){\r
                                        // we search for any file:\r
                                        rc = m_dirs[m_level];\r
index 9c4244b503fd4cd82dfa4ef3ab3a066fdb3f14ee..cb4b1b6679878b8e5dbc738d3c4f9daf88021c6b 100644 (file)
@@ -79,7 +79,7 @@ public:
     static time_t filetimeToTime(const FileTime_t* time);
     static void timeToFiletime(time_t time, FileTime_t& filetime);
 };
-class ReDirEntryFilter_t {
+class ReDirEntryFilter_t{
 public:
        ReDirEntryFilter_t();
        ~ReDirEntryFilter_t();
@@ -95,14 +95,44 @@ public:
        time_t m_maxAge;
     int m_minDepth;
     int m_maxDepth;
-    int m_traceInterval;
-    time_t m_lastTrace;
-    int m_traceCounter;
+};
+class ReTraceUnit{
+public:
+       ReTraceUnit(int m_triggerCount = 10, int interval = 60);
+       virtual ~ReTraceUnit();
+public:
+       /** Returns whether the the instance is triggered.
+        * To avoid too the not cheap call of time() the trace unit uses a counter.
+        * If the counter reaches a given level the time check should be done.
+        * @return <code>true</code>: the counter has reached <code>m_triggerCount</code>
+       */
+       inline bool isCountTriggered(){
+               bool rc = ++m_count % m_triggerCount == 0;
+               return rc;
+       }
+       /** Tests whether a given waiting time has been gone since the last trace.
+        * @return      <code>true</code>: the last trace has been done after
+        *                      at least <code>m_interval</code> seconds
+        */
+       inline bool isTimeTriggered(){
+               time_t now = time(NULL);
+               bool rc = now - m_lastTrace > m_interval;
+               if (rc){
+                       m_lastTrace = now;
+               }
+               return rc;
+       }
+       virtual bool trace(const char* message);
+protected:     
+       int m_count;
+       int m_triggerCount;
+       time_t m_lastTrace;
+       int m_interval;
 };
 #define MAX_ENTRY_STACK_DEPTH 256
 class ReTraverser {
 public:
-       ReTraverser(const char* base);
+       ReTraverser(const char* base, ReTraceUnit* tracer = NULL);
        virtual ~ReTraverser();
 public:
        /**
@@ -176,6 +206,7 @@ protected:
        int m_directories;
        int m_files;
        int64_t m_sizes;
+       ReTraceUnit* m_tracer;
 };
 
 #endif /* OS_RETRAVERSER_HPP_ */