]> gitweb.hamatoma.de Git - crepublib/commitdiff
bug fixing
authorhama <hama@siduction.net>
Sun, 22 Feb 2015 23:24:27 +0000 (00:24 +0100)
committerhama <hama@siduction.net>
Sun, 22 Feb 2015 23:24:27 +0000 (00:24 +0100)
17 files changed:
base/ReByteBuffer.cpp
base/ReByteBuffer.hpp
base/ReDirectory.cpp
base/ReProgramArgs.cpp
base/ReTestUnit.cpp
base/ReVarArgs.cpp
base/rebase.hpp
cunit/cuReByteBuffer.cpp
cunit/cuReDirTools.cpp
cunit/cuReHashList.cpp
cunit/cuReSeqArray.cpp
cunit/cuReTraverser.cpp
os/ReDirTools.cpp
os/ReDirTools.hpp
os/ReTraverser.cpp
os/ReTraverser.hpp
os/reos.hpp

index f12c8d290f698cf6cf1e1dd79d25f97c2f51b462..06e6c3e6ea83bc3d985af3cfc9918e4c1f8b8256 100644 (file)
@@ -211,10 +211,10 @@ ReByteBuffer& ReByteBuffer::appendHexDump(const char* data, size_t length,
                                append("  ");
                        if (ix < bytesPerLine - 1
                                        && (groupWidth == 1 || ix % groupWidth == groupWidth - 1))
-                               append(" ", 1);
+                               appendChar(' ');
                        if (ix < bytesPerLine - 1 && gapBehind > 0
                                        && (gapBehind == 1 || ix % gapBehind == gapBehind - 1))
-                               append(" ", 1);
+                               appendChar(' ');
                }
                if (withAscii){
                        if (separator != NULL)
@@ -229,7 +229,7 @@ ReByteBuffer& ReByteBuffer::appendHexDump(const char* data, size_t length,
                                                && (gapBehind == 1 || ix % gapBehind == gapBehind - 1))
                                        append(" ", 1);
                        }
-                       append("\n", 1);
+                       appendChar('\n');
                        length = length <= (size_t) bytesPerLine ? 0 : length - bytesPerLine;
                        data += bytesPerLine;
                        offset += bytesPerLine;
index 69feda25aaa32ac21877286bc1d60656a2aa422b..590dbce2afca1eec5ae563b897ac5f0b479212d4 100644 (file)
@@ -47,6 +47,28 @@ public:
        ReByteBuffer& append(const Byte* source, size_t length = -1);
        ReByteBuffer& append(const ReByteBuffer& source);
        ReByteBuffer& append(double, const char* format = "%f");
+       /** Appends a character.
+        * @param aChar         character to append
+        * @return                      <code>*this</code> (for chaining)
+        */
+       inline ReByteBuffer& appendChar(char aChar){
+               setLength(m_length + 1);
+               m_buffer[m_length - 1] = aChar;
+               return *this;
+       }
+       /** Appends a character at least one time.
+        * @param aChar         character to append
+        * @param count         number of times to append
+        * @return                      <code>*this</code> (for chaining)
+        */
+       inline ReByteBuffer& appendChar(char aChar, int count){
+               if (count > 0){
+                       size_t oldLength = m_length;
+                       setLength(m_length + count);
+                       memset(m_buffer + oldLength, aChar, count);
+               }
+               return *this;
+       }
        ReByteBuffer& appendHexDump(const char* data, size_t length = -1,
                int offset = 0, int bytePerLine = 16,
                const char* offsetFormat = "%04x: ", bool withAscii = true,
@@ -65,7 +87,7 @@ public:
                return index >= m_length ? 0 : m_buffer[index];
        }
        int atoi(size_t start = 0, int end = -1) const;
-       /** @brief Returns the buffer.
+       /** @brief Returns the buffer (permitting modifying).
         * @return The internal used buffer.
         */
        inline Byte* buffer() const{
@@ -87,11 +109,20 @@ public:
        bool endsWith(const Byte* tail, size_t tailLength = -1,
                                bool ignoreCase = false) const;
        void ensureSize(size_t size);
+       /** After the call the last character is the given.
+        * @param aChar         the character which will be the last
+        * @return                      <code>*this</code> (for chaining)
+        */
+       inline ReByteBuffer& ensureLastChar(char aChar){
+               if (lastChar() != aChar)
+                       appendChar(aChar);
+               return *this;
+       }
        /** @brief Tests whether another instance is equal to this instance.
         * @param buffer        the buffer to compare
         * @return                      <code>true</code>: the buffer's contents are equal
         */
-       inline bool equals(const ReByteBuffer& buffer){
+       inline bool equals(const ReByteBuffer& buffer) const{
                bool rc = buffer.length() == m_length && _memcmp(buffer.str(), m_buffer, m_length) == 0;
                return rc;
        }
@@ -120,12 +151,31 @@ public:
        inline bool insert(size_t ix, const Byte* source, size_t length){
                return splice(ix, 0, source, length);
        }
+       /** Returns the last character.
+        * @return      '\0': empty buffer<br>
+        *                      otherwise: the last character
+        */
+       inline char lastChar() const {
+               return m_length == 0 ? '\0' : m_buffer[m_length - 1];
+       }
        /**@brief Returns the length of the buffer (the count of used bytes).
         * @return The count of the allocated bytes in the internal buffer.
         */
        inline size_t length() const{
                return m_length;
        }
+       /** Sets the length to a lower value.
+        * @param decrement             the count to reduce the length
+        * @return The count of the allocated bytes in the internal buffer.
+        */
+       inline ReByteBuffer& reduceLength(int decrement = 1){
+               if (decrement > 0 && m_length > 0){
+                       if (decrement > m_length)
+                               decrement = m_length;
+                       setLength(m_length - decrement);
+               }
+               return *this;
+       }
        /** @brief Cuts a sequence from the internal buffer.
         *
         * @param ix                            The index where the cut/insertion takes place.
@@ -139,6 +189,15 @@ public:
        }
        ReByteBuffer& replaceAll(const Byte* toFind, size_t toFindLength,
                        const Byte* replacement, size_t replacementLength, int start = 0);
+       /** Removes an unwanted character at the end.
+        * @param aChar         character to remove
+        * @return                      <code>*this</code> (for chaining)
+        */
+       inline ReByteBuffer& removeLastChar(char aChar){
+               if (m_length > 0 && m_buffer[m_length - 1] == aChar)
+                       setLength(m_length - 1);
+               return *this;
+       }
        /** @brief Finds the index of the last occurrence of a given byte (reverse index of).
         * @param toFind        This byte will be searched.
         * @param start         The first index for searching. If &lt; 0: relative to the end.
index 1982c94b0a048769f6abc131cbd2a8f64fecc9a9..64fe2e00902825e78a26b12903b37793e75e5e80 100644 (file)
@@ -292,12 +292,11 @@ void ReDirectory::setDir(const char* path){
 #elif defined __WIN32__
     struct stat info;
     ReByteBuffer thePath(m_path);
-    if (m_path.endsWith(OS_SEPARATOR))
-        thePath.setLength(thePath.length() - 1);
+    thePath.removeLastChar(OS_SEPARATOR_CHAR);
     m_valid = stat(thePath.str(), &info) == 0 && S_ISDIR(info.st_mode);
 #endif
-       if (m_path.at(m_path.length() - 1) != OS_SEPARATOR_CHAR)
-               m_path.append(OS_SEPARATOR, 1);
+       if (m_path.lastChar() != OS_SEPARATOR_CHAR)
+               m_path.appendChar(OS_SEPARATOR_CHAR);
 }
 
 /** @brief Sets the flags of the regular expression handling.
index 701a742375898b4601a98e97cc317e9db6084a79..139a9d6bf9d121fcaef4e2f299ca6eb456d8faa2 100644 (file)
@@ -57,8 +57,7 @@ ReProgramArgs::ReProgramArgs(const char* usageList[], const char* examples[])
        ReByteBuffer line;
        for (const char** argv = usageList; *argv != NULL; argv++){
                line.set(*argv);
-               if (line.endsWith("\n"))
-                       line.setLength(line.length() - 1);
+               line.removeLastChar('\n');
                m_usage.append(line.str());
        }
        if (examples != NULL){
@@ -141,12 +140,12 @@ void ReProgramArgs::addProperties(const char*name, const char* description, char
     ReByteBuffer replacement("\n", 1);
     replacement.append(PREFIX_LINE_OPTION);
     descr.replaceAll("\n", 1, replacement.str(), replacement.length());
-       properties.append(descr).append("\1", 1);
-       properties.append(&shortOpt, 1).append("\1", 1);
-       properties.append(longOpt, strlen(longOpt)).append("\1", 1);
-       properties.append((char*) &dataType, 1).append("\1", 1);
+       properties.append(descr).appendChar('\1');
+       properties.append(&shortOpt, 1).appendChar('\1');
+       properties.append(longOpt, strlen(longOpt)).appendChar('\1');
+       properties.append((char*) &dataType, 1).appendChar('\1');
        properties.append(defaultValue == NULL ? "" : defaultValue, 
-        lengthValue).append("\1", 1);
+        lengthValue).appendChar('\1');
        m_properties.put(name, properties.str());
 
        // Mark current value as default:
@@ -380,7 +379,7 @@ void ReProgramArgs::setValue(const char* name, const char* value, const char* da
        }
        ReByteBuffer buffer;
        // First character says: defined.
-       buffer.append(" ", 1).append(value, -1);
+       buffer.appendChar(' ').append(value, -1);
        m_values.put(name, buffer.str());
 }
 /** @brief Analyses one or more short name options.
@@ -583,7 +582,7 @@ void ReProgramArgs::help(const char* message, bool issueLastError,
                }
                if (shortName[0] != HIDDEN_SHORT_NAME){
                        line.append("-", 1).append(shortName, 1);
-                       line.append(param.str(), -1).append(" ", 1).append(i18n(" or "), -1);
+                       line.append(param.str(), -1).appendChar(' ').append(i18n(" or "), -1);
                }
                line.append(i18n("--"), -1).append(properties.strOf(IxLong), -1);
                if (param.length() > 0){
@@ -591,10 +590,10 @@ void ReProgramArgs::help(const char* message, bool issueLastError,
             if (dataType != DT_STRING || properties.strLengthOf(IxDefault) > 0){
                                line.append(i18n(" Default value: "), -1);
                 if (dataType == DT_STRING)
-                    line.append("'", 1);
+                    line.appendChar('\'');
                 line.append(properties.strOf(IxDefault), -1);
                 if (dataType == DT_STRING)
-                    line.append("'", 1);
+                    line.appendChar('\'');
             }
         }
                lines.append(line.str());
index 9d89d5c78bace29efe8dafed9a30fd1bd3f7f823..7797d2fa0f8d8e02cd107ba9892dd67b46b05e03 100644 (file)
@@ -208,7 +208,7 @@ const char* ReTestUnit::colMarker(int col){
                m_buffer.fill('-', 0, col - 1);
        else
                m_buffer.setLength(0);
-       m_buffer.append("^", 1);
+       m_buffer.appendChar('^');
        return m_buffer.str();
 }
 
index 77f24743a7c5bd020af82e51f3fb2ac352a6cda8..4188be4bc92fa2d6dba42044f2c4f9c715ff3011 100644 (file)
@@ -163,7 +163,7 @@ void ReVarArgs::store(const char* value, int length){
        m_args[++m_argNo] = m_argBuffer.length();
                // Store the string with trailing '\0':
        m_argBuffer.append(value, length);
-       m_argBuffer.append("", 1);
+       m_argBuffer.appendChar('\0');
        if (m_trigger != NULL)
                m_trigger->newArg(m_argNo, m_maxArgNo);
 }
index 1a8407c580b6d767597ab31796750a95e4c0da7d..d9bfbbe6240bdb54d2977f54d2d008a277352a89 100644 (file)
@@ -42,6 +42,7 @@
 #      define _snprintf snprintf
 #      define _memcmp(t,s,n) memcmp(t,s,n)
 #      define _mkdir(path, mode) mkdir(path, mode)
+#      define _rmdir(path) rmdir(path)
 #      define OS_SEPARATOR_CHAR '/'
 #      define OS_SEPARATOR "/"
 #elif defined __WIN32__
index b4fe8be2e80f91b44cabfa2574c00b5591a0af96..3bb497a6fbe62152381b590cccb3c9689ad64fc7 100644 (file)
@@ -15,6 +15,11 @@ public:
        }
 private:
        void run(){
+               testEnsureLastChar();
+               testLastChar();
+               testReduceLength();
+               testRemoveLastChar();
+               testAppendChar();
                testAppendFloat();
                testAppendInt64();
                testEnsureSize2();
@@ -40,6 +45,67 @@ private:
                testSplice();
                testReplace();
        }
+       void testEnsureLastChar(){
+               ReByteBuffer buffer("1/");
+               buffer.ensureLastChar('/');
+               checkEqu(2, buffer.length());
+               checkEqu('/', buffer.lastChar());
+               buffer.ensureLastChar('x');
+               checkEqu(3, buffer.length());
+               checkEqu('x', buffer.lastChar());
+       }
+       void testLastChar(){
+               ReByteBuffer buffer("12345");
+               checkEqu('5', buffer.lastChar());
+               buffer.setLength(0);
+               checkEqu('\0', buffer.lastChar());
+       }
+       void testReduceLength(){
+               ReByteBuffer buffer("12345");
+               buffer.reduceLength();
+               checkEqu(4, buffer.length());
+               checkEqu("1234", buffer.str());
+               buffer.reduceLength(2);
+               checkEqu(2, buffer.length());
+               checkEqu("12", buffer.str());
+               buffer.reduceLength(0).reduceLength(-1);
+               checkEqu(2, buffer.length());
+               checkEqu("12", buffer.str());
+               buffer.reduceLength(99);
+               checkEqu(0, buffer.length());
+       }
+       void testRemoveLastChar(){
+               ReByteBuffer buffer("123");
+               buffer.removeLastChar('x').removeLastChar('3');
+               checkEqu(2, buffer.length());
+               checkEqu("12", buffer.str());
+       }
+       void testAppendChar(){
+               ReByteBuffer buffer;
+               buffer.appendChar('1');
+               checkEqu(1, buffer.length());
+               checkEqu("1", buffer.str());
+               buffer.appendChar('2');
+               checkEqu(2, buffer.length());
+               checkEqu("12", buffer.str());
+
+               buffer.appendChar('x', 1);
+               checkEqu(3, buffer.length());
+               checkEqu("12x", buffer.str());
+
+               buffer.appendChar('y', 3);
+               checkEqu(6, buffer.length());
+               checkEqu("12xyyy", buffer.str());
+
+               buffer.appendChar('x', 0);
+               checkEqu(6, buffer.length());
+               checkEqu("12xyyy", buffer.str());
+
+               buffer.appendChar('x', -1);
+               checkEqu(6, buffer.length());
+               checkEqu("12xyyy", buffer.str());
+
+       }
        void testAppendFloat(){
                ReByteBuffer buffer;
 
index 60d47e20d02aeb237fb6403bdbbcbb9a1ef2e0dc..16ffc9926a8c418eb638dcd23dda3101d0576b4a 100644 (file)
 #include "os/reos.hpp"
 
 static const char* s_empty[] = { NULL };
+// count of seconds from 1.1.1970 until 1.1.1980:
+const int tenYear = (365 * 10 + 2) * 24 * 3600;
 
 class TestReDirTools : public ReTestUnit {
 public:
-       TestReDirTools() : ReTestUnit("ReTraverser", __FILE__){
+       TestReDirTools() : ReTestUnit("ReDirTools", __FILE__){
         m_base = testDir();
                ReDirectory::deleteTree(m_base.str());
-        m_base.append("traverser").append(OS_SEPARATOR, -1);
+        m_base.append("dirtool");
         _mkdir(m_base.str(), ALLPERMS);
+               m_base.append(OS_SEPARATOR, -1);
                run();
+               ReDirectory::deleteTree(m_base.str(), true);
        }
 private:
     ReByteBuffer m_base;
@@ -62,8 +66,7 @@ private:
        void run(){
                initTree();
 
-        testTouch();
-               testDirStatistic();
+        testBatch();
 
                testToolStatistic();
                testBasic();
@@ -73,6 +76,7 @@ private:
         testCopyFile();
         testList();
                testToolSync();
+               testBatch();
        }
     void testList(){
         const char* argv[] = { "list", m_base.str(), NULL };
@@ -102,7 +106,8 @@ private:
     }
 
     void checkRelDate(ReFileTime_t absTime, int relTime){
-        int diff = int(time(NULL) - relTime - secOfFileTime(absTime));
+        int diffNow = int(time(NULL) - secOfFileTime(absTime));
+               int diff = diffNow + relTime;
         if (diff < 0)
             diff = - diff;
         checkT(diff < 2);
@@ -130,13 +135,12 @@ private:
 
         // local time: +3600
         const int DIFF = 3600;
-               const int tenYear = (365 * 10 + 2) * 24 * 3600;
         checkEqu(tenYear + 24*60*60 - DIFF, secOfFileTime(opts.checkDate("1980.01.02")));
         checkEqu(tenYear + 24*60*60+3600-DIFF, secOfFileTime(opts.checkDate("1980.01.02/1")));
         checkEqu(tenYear + 24*60*60 + 2*3600 + 33*60 - DIFF, secOfFileTime(opts.checkDate("1980.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);
+        checkRelDate(opts.checkDate("now-3m"), 3*60);
+        checkRelDate(opts.checkDate("now-7h"), 7*60*60);
+        checkRelDate(opts.checkDate("now-5d"), 5*24*60*60);
 
         checkEqu(125ll, opts.checkSize("125"));
         checkEqu(125ll, opts.checkSize("125b"));
@@ -159,8 +163,8 @@ private:
         opts.setFilterFromProgramArgs(filter);
         // local time: +3600
         const int DIFF = 3600;
-        checkEqu(1*24*3600 - DIFF, secOfFileTime(filter.m_maxAge));
-        checkEqu(2*24*3600 - DIFF, secOfFileTime(filter.m_minAge));
+        checkEqu(tenYear + 1*24*3600 - DIFF, secOfFileTime(filter.m_maxAge));
+        checkEqu(tenYear + 2*24*3600 - DIFF, secOfFileTime(filter.m_minAge));
         checkEqu(5, (int) filter.m_maxDepth);
         checkEqu(1, (int) filter.m_minDepth);
         checkEqu(1000ll, filter.m_minSize);
@@ -227,7 +231,7 @@ private:
         checkT(buffer.endsWith(expected.str()));
 
         buffer.set(list.strOf(1), list.strLengthOf(1));
-        checkT(buffer.startsWith("      0.000054 MB       2       3\t"));
+        checkT(buffer.startsWith("      0.000008 MB       1       0\t"));
         expected.set(m_base.str(), m_base.length()).append("dir2", -1)
              .append(OS_SEPARATOR);
         checkT(buffer.endsWith(expected.str()));
@@ -259,8 +263,10 @@ private:
                        cols.split(expected.strOf(ix), '*');
                        if (! line.startsWith(cols.strOf(0)))
                                checkEqu(cols.strOf(0), line.str());
-                       if (! line.endsWith(cols.strOf(1)))
-                               checkEqu(cols.strOf(1), line.str());
+                       const char* col2 = cols.strOf(1);
+                       if (! line.endsWith(col2)){
+                               checkEqu(col2, line.str());
+                       }
                }
     }
     void testTouch(){
@@ -274,23 +280,47 @@ private:
                tools.main(8, (char**) argv);
 
                checkFile(nameCurrent,
-                       "2015.03.28 10:21:31 *traverser/1.txt\n"
-                       "2015.03.28 10:21:31 *traverser/dir1/dir1_2/dir1_2_1/x1.txt\n"
-                       "2015.03.28 10:21:31 *traverser/dir1/dir1_2/dir1_2_1/x2.txt\n"
+                       "2015.03.28 10:21:31 *dirtool/1.txt\n"
+                       "2015.03.28 10:21:31 *dirtool/dir1/dir1_2/dir1_2_1/x1.txt\n"
+                       "2015.03.28 10:21:31 *dirtool/dir1/dir1_2/dir1_2_1/x2.txt\n"
                        "=== filtered:        3 file(s)     0.000059 MByte       0 dirs(s) */sec\n"
                        "===    total:        4 file(s)     0.000067 MByte       6 dirs(s) * sec");
 
-               const char* argv2[] = { "dt", "list", "-P;*;-cache", "-tr", "-p;*.txt",
+               const char* argv2[] = { "dt", "list", "-P;*;-cache", "-tr", "-p;*.txt", "-h",
                        optOutput.str(), m_base.str(), NULL };
-               tools.main(7, (char**) argv2);
+               tools.main(8, (char**) argv2);
 
                checkFile(nameCurrent,
-                       "     0.000005 2015.03.28 10:21:31 02 *traverser/1.txt\n"
-                       "     0.000027 2015.03.28 10:21:31 02 *traverser/dir1/dir1_2/dir1_2_1/x1.txt\n"
-                       "     0.000027 2015.03.28 10:21:31 02 *traverser/dir1/dir1_2/dir1_2_1/x2.txt\n"
-                       "===        3 file(s)     0.000059 MByte       0 dirs(s) * sec");
+                       "      0.000005 2015.03.28 10:21:31 *dirtool/1.txt\n"
+                       "      0.000027 2015.03.28 10:21:31 *dirtool/dir1/dir1_2/dir1_2_1/x1.txt\n"
+                       "      0.000027 2015.03.28 10:21:31 *dirtool/dir1/dir1_2/dir1_2_1/x2.txt\n"
+                       "=== filtered:        3 file(s)     0.000059 MByte       0 dirs(s) */sec\n"
+                       "===    total:        4 file(s)     0.000067 MByte       6 dirs(s) * sec");
 
        }
+    void testBatch(){
+               ReByteBuffer nameCurrent;
+               buildFilename("current", nameCurrent);
+               ReByteBuffer optOutput("--output-file=");
+               optOutput.append(nameCurrent);
+               ReDirTools tools;
+               const char* argv[] = { "dt", "batch", "-P;*;-cache", "-td", "-cmyscript",
+                       optOutput.str(), m_base.str(), NULL };
+               tools.main(7, (char**) argv);
+               ReByteBuffer content("#! /bin/sh*\n"
+                       "myscript '*dirtool/dir1'\n"
+                       "myscript '*dirtool/dir2'\n"
+                       "myscript '*dirtool/dir1/dir1_1'\n"
+                       "myscript '*dirtool/dir1/dir1_2'\n"
+                       "myscript '*dirtool/dir1/cache'\n"
+                       "myscript '*dirtool/dir1/dir1_2/dir1_2_1'\n"
+                       "# === filtered:        0 file(s)     0.000000 MByte       6 dirs(s) */sec\n"
+                       "# ===    total:        4 file(s)     0.000067 MByte       6 dirs(s) * sec");
+#if defined __WIN32__
+               content.replaceAll("'", 1, "\"", 1);
+#endif
+               checkFile(nameCurrent, content.str());
+       }
        void testToolStatistic(){
                ReDirTools tools;
                const char* argv[] = { "dt", "stat", "-P;*;-cache", m_base.str(), "2" };
index 6990a6e7d2f56fc80d0da53bbd5f3a3712aeb7f1..f6820ba217a5bcfe595e8cc9a726cba04f5f57c2 100644 (file)
@@ -37,10 +37,10 @@ private:
                for(ix = 0; ix < maxKeys; ix++){
                        rand.nextString(minLength, maxLength, key);
                        if (hash.get(key, value)){
-                               value.append("+", 1);
+                               value.appendChar('+');
                                collisions++;
                        } else {
-                               value.set(key).append("X", 1);
+                               value.set(key).appendChar('X');
                        }
                        hash.put(key, value);
                }
index 20bda85310567fd189578c1f9b7055350a579134..8d5fe540672f71326e7b45f4c5f02365b92839a9 100644 (file)
@@ -158,7 +158,7 @@ private:
                expectedValue.setLength(0);
                for (size_t ix = 0; ix < maxIx; ix++){
                        expectedTag = (1ll << ix);
-                       expectedValue.append("x", 1);
+                       expectedValue.appendChar('x');
                        checkT(list.get(ix, value, &tag));
                        checkEqu(expectedValue.str(), value.str());
                        checkEqu(expectedTag, tag);
@@ -173,7 +173,7 @@ private:
                size_t maxIx = 13;
                for (size_t ix = 0; ix < maxIx; ix++){
                        expectedTag = 10*ix;
-                       expectedValue.append("x", 1);
+                       expectedValue.appendChar('x');
                        list.add(-1, expectedValue.str(), -1, expectedTag);
                        checkEqu(ix + 1, list.count());
                        checkT(list.get(ix, value, &tag));
@@ -185,7 +185,7 @@ private:
                expectedValue.setLength(0);
                for (size_t ix = 0; ix < maxIx; ix++){
                        expectedTag = -1;
-                       expectedValue.append("x", 1);
+                       expectedValue.appendChar('x');
                        if (ix >= 4)
                                expectedTag = -1;
                        checkEqu(ix, list.find(expectedValue.str(), expectedValue.length(), &expectedTag));
index 0d21f1fa90accd6d9a42e221e788ee86792c3cae..8d96896676aa1e288eba151b888bb995cfe65cd8 100644 (file)
@@ -16,9 +16,11 @@ class TestReTraverser : public ReTestUnit {
 public:
        TestReTraverser() : ReTestUnit("ReTraverser", __FILE__){
         m_base = testDir();
-        m_base.append("traverser").append(OS_SEPARATOR, -1);
+        m_base.append("traverser");
         _mkdir(m_base.str(), ALLPERMS);
+               m_base.append(OS_SEPARATOR, -1);
                run();
+               ReDirectory::deleteTree(m_base.str(), true);
        }
 private:
     ReByteBuffer m_base;
@@ -104,7 +106,7 @@ private:
                ReTraverser traverser(m_base.str());
                RePatternList patterns;
                // exclude */cache/*
-               ReByteBuffer buffer(";*;-*/cache");
+               ReByteBuffer buffer(";*;-cache");
                patterns.set(buffer.str());
                traverser.setDirPattern(&patterns);
                int level = 0;
index 32b34b6b108d79ead4631f947edf5729b893a7d8..ceb6019bab65b013260b92984b68608349d8eda2 100644 (file)
@@ -299,15 +299,17 @@ ReFileTime_t ReDirOptions::checkDate(const char* value){
         // a time distance value:\r
         char unit = 'm';\r
         int count = 0;\r
-               int isNegative = false;\r
-               if (theValue.startsWith("now")){\r
-                       rcTime = time(NULL);\r
+               bool negativeFactor = 1;\r
+               bool fromNow = theValue.startsWith("now");\r
+               if (fromNow){\r
                        theValue.remove(0, 3);\r
                }\r
-               if (theValue.str()[0] == '-')\r
-                       isNegative = true;\r
-               else if (theValue.startsWith("+"))\r
+               char cc = theValue.at(0);\r
+               if (cc == '-' || cc == '+'){\r
+                       if (cc == '-')\r
+                               negativeFactor = -1;\r
                        theValue.remove(0, 1);\r
+               }\r
         switch(sscanf(theValue.str(), "%d%c", &count, &unit)){\r
         case 1:\r
         case 2:\r
@@ -327,17 +329,15 @@ ReFileTime_t ReDirOptions::checkDate(const char* value){
                 throw ReOptionException(&m_programArgs, \r
                     i18n("invalid unit $1. expected: s(econds) m(inutes) h(ours) d(ays)"), value);\r
             }\r
-            rcTime = time(NULL) - count;\r
+            rcTime = count * negativeFactor;\r
             break;\r
         default:\r
             throw ReOptionException(&m_programArgs, \r
                 i18n("invalid relative time value $1 (<number><unit> expected). <unit>: s m h d"),\r
                 value);\r
         }\r
-        if (isNegative)\r
-                       rcTime -= count;\r
-               else\r
-                       rcTime += count;\r
+        if (fromNow)\r
+                       rcTime += time(NULL);\r
     }\r
     ReFileTime_t rc;\r
        ReDirStatus_t::timeToFiletime(rcTime, rc);\r
@@ -524,10 +524,10 @@ void ReDirOptions::checkStandardFilterOptions(){
  * Frees the resources.\r
  */\r
 void ReDirOptions::close(){\r
-       if (m_output != stdout){\r
+       if (m_output != stdout && m_output != stderr){\r
                fclose(m_output);\r
-               m_output = stdout;\r
        }\r
+       m_output = stdout;\r
 }\r
 \r
 /**\r
@@ -564,8 +564,7 @@ void ReDirOptions::optimizePathPattern(ReByteBuffer& buffer){
                item.set(list.strOf(ix), -1);\r
                if (item.endsWith("/*"))\r
                        item.setLength(item.length() - 2);\r
-               if (item.endsWith("/"))\r
-                       item.setLength(item.length() - 1);\r
+               item.removeLastChar('/');\r
                bool notAnchored = item.startsWith("*/") || item.startsWith("-*/");\r
                item.replaceAll("/", 1, OS_SEPARATOR, 1);\r
                list.replace(ix, item.str());\r
@@ -666,8 +665,8 @@ bool ReTool::trace(const char* currentFile){
        ReByteBuffer buffer(" ");\r
        int duration = int(time(NULL) - m_startTime);\r
        buffer.appendInt(duration / 60).appendInt(duration % 60, ":%02d: ");\r
-       buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.directories()).append(" dir(s)");\r
-       buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.files()).append(" file(s)");\r
+       buffer.appendInt(m_files).appendChar('/').appendInt(m_traverser.directories()).append(" dir(s)");\r
+       buffer.appendInt(m_files).appendChar('/').appendInt(m_traverser.files()).append(" file(s)");\r
        buffer.append(currentFile);\r
        fputs(buffer.str(), stdout);\r
        return true;\r
@@ -734,7 +733,7 @@ void ReTool::processSingleFile(const char* filename){
        if (protocol.length() == 0)\r
                protocol.append(".");\r
        else\r
-               protocol.setLength(protocol.length() - 1);\r
+               protocol.reduceLength();\r
        m_traverser.changeBase(protocol.str());\r
 \r
        name.append(ext);\r
@@ -806,7 +805,7 @@ void ReTool::printSummary(const char* prefix){
                double rate = duration == 0 ? 0.0 : (m_files + m_directories) / duration;\r
                line.append(rate, " %.1f").append(i18n("/sec"), -1);\r
                m_traverser.statisticAsString(line2);\r
-               line2.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec"));\r
+               line2.appendChar(' ').appendTime(duration).append(" ", 1).append(i18n("sec"));\r
                fprintf(m_output, "%s=== filtered: %s\n", prefix == NULL ? "" : prefix, line.str());\r
                fprintf(m_output, "%s===    total: %s\n", prefix == NULL ? "" : prefix, line2.str());\r
        }\r
@@ -899,7 +898,8 @@ ReDirBatch::ReDirBatch() :
     ReTool(s_batchUsage, s_batchExamples, 0, 0, 0, true),\r
        m_arguments(),\r
     m_script(),\r
-    m_isExe(false)\r
+    m_isExe(false),\r
+    m_first()\r
 {\r
        // standard short options: D d O o P p T t v y Z z\r
     m_programArgs.addString("first",\r
@@ -973,7 +973,7 @@ static void replaceMakros(const char* arguments, ReDirStatus_t* entry, const cha
     }\r
     // We remove the unwanted delimiters (see above):\r
     ReByteBuffer buffer;\r
-    buffer.set(delim, -1).append("\x01", 1).append(delim, -1);\r
+    buffer.set(delim, -1).appendChar('\01').append(delim, -1);\r
     line.replaceAll(buffer.str(), buffer.length(), "", 0);\r
 }\r
 /**\r
@@ -981,25 +981,21 @@ static void replaceMakros(const char* arguments, ReDirStatus_t* entry, const cha
  */\r
 void ReDirBatch::doIt(){\r
        ReByteBuffer buffer;\r
-       m_arguments.append(m_programArgs.getString("arguments", buffer), -1);\r
-       m_script.append(m_programArgs.getString("script", buffer), -1);\r
+       m_programArgs.getString("arguments", m_arguments);\r
+       m_programArgs.getString("script", m_script);\r
        if (m_arguments.length() + m_script.length() == 0)\r
                help(i18n("one of the option must be set: -a (--arguments) or -c (--script)"));\r
 #if defined __WIN32__\r
        m_isExe = m_programArgs.getBool("isexe");\r
 #endif\r
+       m_programArgs.getString("first", m_first);\r
        processFileArguments();\r
-       if (m_verboseLevel >= V_SUMMARY){\r
-               int duration = int(time(NULL) - m_start);\r
 #if defined __linux__\r
-               const char* prefix = "#";\r
+       static const char* prefix = "# ";\r
 #elif defined __WIN32__\r
-               const char* prefix = "rem";\r
+       static const char* prefix = "rem ";\r
 #endif\r
-               statisticAsString(buffer);\r
-               buffer.append(" ").appendTime(duration);\r
-               fprintf(m_output, "%s %s\n", buffer.str());\r
-       }\r
+       printSummary(prefix);\r
 }\r
 \r
 /**\r
@@ -1023,14 +1019,18 @@ void ReDirBatch::processFile(ReDirStatus_t* entry){
 #elif defined __WIN32__\r
        static const char* delim = "\"";\r
 #endif\r
+       if (m_first.length() > 0){\r
+               fprintf(m_output, "%s\n", m_first.str());\r
+               m_first.setLength(0);\r
+       }\r
        if (m_script.length() > 0){\r
 #if defined __WIN32__\r
                if (! m_isExe)\r
                        line.append("call ");\r
 #endif\r
-               line.append(m_script).append(" ").append(delim, -1);\r
+               line.append(m_script).appendChar(' ').appendChar(delim[0]);\r
                line.append(entry->m_path).append(entry->node(), -1);\r
-               line.append(delim, -1);\r
+               line.appendChar(delim[0]);\r
        } else {\r
                replaceMakros(m_arguments.str(), entry, delim, line);\r
        }\r
@@ -1042,10 +1042,17 @@ void ReDirBatch::processFile(ReDirStatus_t* entry){
  */\r
 ReDirList::ReDirList() :\r
     ReTool(s_listUsage, s_listExamples, 0, 0, 0, true),\r
-    m_shortFormat(false)\r
+    m_shortFormat(false),\r
+    m_hideRights(false),\r
+    m_numerical(false)\r
 {\r
+       // standard short options: D d O o P p T t v y Z z\r
     m_programArgs.addBool("short", i18n("output is only path and basename"),\r
         '1', "--short", false);\r
+    m_programArgs.addBool("rights", i18n("do not show the permission/right info"),\r
+        'h', "--hide-rights", false);\r
+    m_programArgs.addBool("numerical", i18n("the permission/right info is shown as numbers"),\r
+        'n', "--numerical", false);\r
     addStandardFilterOptions();\r
 }\r
 \r
@@ -1054,14 +1061,10 @@ ReDirList::ReDirList() :
  */\r
 void ReDirList::doIt(){\r
        m_shortFormat = m_programArgs.getBool("short");\r
+       m_hideRights = m_programArgs.getBool("rights");\r
+       m_numerical = m_programArgs.getBool("numerical");\r
        processFileArguments();\r
-       if (m_verboseLevel >= V_SUMMARY){\r
-               int duration = int(time(NULL) - m_start);\r
-               ReByteBuffer line;\r
-               statisticAsString(line);\r
-               line.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec"));\r
-               fprintf(m_output, "=== %s\n", line.str());\r
-       }\r
+       printSummary();\r
 }\r
 \r
 /**\r
@@ -1082,13 +1085,16 @@ void ReDirList::processFile(ReDirStatus_t* entry){
        ReByteBuffer bufferTime;\r
        if (m_shortFormat)\r
                fprintf(m_output, "%s%s\n", entry->m_path.str(), entry->node());\r
-       else\r
-               fprintf(m_output, "%s %12.6f %s %02x %s%s\n",\r
-                       entry->rightsAsString(bufferRights),\r
+       else {\r
+               if (! m_hideRights)\r
+                       entry->rightsAsString(bufferRights, m_numerical);\r
+               fprintf(m_output, "%c%s %12.6f %s %s%s\n",\r
+                       entry->typeAsChar(),\r
+                       bufferRights.str(),\r
                        entry->fileSize() / 1E6,\r
                        entry->filetimeAsString(bufferTime),\r
-                       entry->type(),\r
                        entry->m_path.str(), entry->node());\r
+       }\r
 }\r
 \r
 \r
@@ -1666,13 +1672,12 @@ bool ReDirSync::makeDirectory(const char* directory, int minLength,
 #if defined __WIN32__\r
        start = path.indexOf(':');\r
 #endif\r
+       path.ensureLastChar(OS_SEPARATOR_CHAR);\r
        int ixSlash = start < 0 ? 0 : start;\r
        struct stat info;\r
        // for all parents and the full path itself:\r
        while(ixSlash >= 0){\r
                ixSlash = path.indexOf(OS_SEPARATOR_CHAR, ixSlash + 1);\r
-        if (ixSlash >= (int) path.length() - 1)\r
-            break;\r
                // is the slash in front of the first node, e.g. 'e:\'?\r
                if (ixSlash == start + 1)\r
                        // not a real node: take the next node\r
@@ -1713,8 +1718,7 @@ void ReDirSync::doIt(){
     const char* sep = OS_SEPARATOR;\r
        ReByteBuffer buffer;\r
        ReByteBuffer target(m_programArgs.getArg(m_programArgs.getArgCount() - 1));\r
-       if (target.endsWith(OS_SEPARATOR))\r
-               target.setLength(target.length() - 1);\r
+       target.removeLastChar(OS_SEPARATOR_CHAR);\r
        if (! exists(target))\r
                help(i18n("target does not exist: $1"), target.str());\r
        else if (! S_ISDIR(m_statInfo.st_mode))\r
@@ -1737,7 +1741,7 @@ void ReDirSync::doIt(){
                target.setLength(lengthTargetBase);\r
                bool endsWithSlash = source.endsWith(sep, 1);\r
                if (endsWithSlash)\r
-                       source.setLength(source.length() - 1);\r
+                       source.reduceLength();\r
                if (! exists(source))\r
                        help(i18n("source does not exist: $1"), source.str());\r
                else if (! S_ISDIR(m_statInfo.st_mode))\r
@@ -1745,25 +1749,25 @@ void ReDirSync::doIt(){
                if (! endsWithSlash){\r
                        // the basename of the source will be appended to the target:\r
                        int startNode = source.rindexOf(sep, 1, 0, source.length() - 1);\r
-                       target.append(OS_SEPARATOR, 1);\r
+                       target.appendChar(OS_SEPARATOR_CHAR);\r
                        target.append(source.str() + startNode + 1, -1);\r
                }\r
                size_t ixSourceRelative = source.length();\r
                size_t ixTargetRelative = target.length();\r
 \r
-               ReTraverser traverser(source.str());\r
-               traverser.setPropertiesFromFilter(&filter);\r
+               m_traverser.changeBase(source.str());\r
+               m_traverser.setPropertiesFromFilter(&filter);\r
                int level;\r
                ReDirStatus_t* entry;\r
                ReByteBuffer line;\r
-               while( (entry = traverser.nextFile(level, &filter)) != NULL){\r
+               while( (entry = m_traverser.nextFile(level, &filter)) != NULL){\r
                        if (entry->isDirectory())\r
                                continue;\r
                        // append the new relative path from source to target:\r
                        target.setLength(ixTargetRelative);\r
                        target.append(entry->m_path.str() + ixSourceRelative, -1);\r
                        if (! exists(target))\r
-                               makeDirWithParents(target, ixTargetRelative, traverser);\r
+                               makeDirWithParents(target, ixTargetRelative, m_traverser);\r
                        targetFile.set(target).append(entry->node(), -1);\r
                        const char* targetRelativePath = targetFile.str() + ixTargetRelative + 1;\r
                        bool targetExists = exists(targetFile);\r
@@ -1800,9 +1804,9 @@ void ReDirSync::doIt(){
                        if (! dry)\r
                                copyFile(entry, targetFile.str());\r
                }\r
-               treeFiles += traverser.files();\r
-               treeDirs += traverser.directories();\r
-               treeSumSizes+= traverser.sizes();\r
+               treeFiles += m_traverser.files();\r
+               treeDirs += m_traverser.directories();\r
+               treeSumSizes+= m_traverser.sizes();\r
        }\r
        if (m_verboseLevel >= V_SUMMARY){\r
                int duration = int(time(NULL) - m_start);\r
@@ -1902,7 +1906,6 @@ int ReDirTools::main(int argc, char* orgArgv[]){
         testAll();\r
     }else\r
         tools.usage("unknown command: ", argv[1]);\r
-       ReLogger::freeGlobalLogger();\r
     return 0;\r
 }\r
 \r
index 2fcf836537ecbb6c068b199991a22caaa7184040..8985ec629ec3814e6bd7769e87c1fc0f578acffa 100644 (file)
@@ -137,7 +137,7 @@ protected:
        ReByteBuffer m_arguments;
     ReByteBuffer m_script;
        bool m_isExe;
-
+       ReByteBuffer m_first;
 };
 
 /**
@@ -152,6 +152,8 @@ protected:
        virtual void processFile(ReDirStatus_t* entry);
 protected:
        bool m_shortFormat;
+       bool m_hideRights;
+       bool m_numerical;
 };
 
 /**
index 20e8d140925703877db3efdc4fcb0dda6c0d70d4..6c96df616b0a585c323935b05483e279097ff9df 100644 (file)
@@ -34,48 +34,29 @@ ReDirStatus_t::ReDirStatus_t() :
 }\r
 \r
 /**\r
- * Frees the resources of an instance.\r
- */\r
-void ReDirStatus_t::freeEntry(){\r
-#if defined __linux__\r
-       if (m_handle != NULL){\r
-               closedir(m_handle);\r
-               m_handle = NULL;\r
-       }\r
-#elif defined __WIN32__\r
-       if (m_handle != INVALID_HANDLE_VALUE){\r
-               FindClose(m_handle);\r
-               m_handle = INVALID_HANDLE_VALUE;\r
-       }\r
-#endif\r
-       m_path.setLength(0);\r
-       m_fullName.setLength(0);\r
-}\r
-\r
-/**\r
- * Returns the name of the current file (without path).\r
+ * Returns the last access time.\r
  *\r
- * @return     the name of the current file.\r
+ * @return     the last access time\r
  */\r
-const char* ReDirStatus_t::node() const{\r
+const ReFileTime_t* ReDirStatus_t::accessed() {\r
 #ifdef __linux__\r
-    return m_data->d_name;\r
+    return &(getStatus()->st_atim);\r
 #elif defined __WIN32__\r
-    return m_data.cFileName;\r
+    return &m_data.ftLastAccessTime;\r
 #endif\r
 }\r
+\r
 /**\r
- * Returns the file rights as a string.\r
+ * Returns the filesize.\r
  *\r
- * @param buffer    OUT: the file rights\r
- * @return          <code>buffer.str()</code> (for chaining)\r
+ * @return     the filesize\r
  */\r
-const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer) {\r
-    buffer.setLength(0);\r
-#if defined __linux__\r
+ReFileSize_t ReDirStatus_t::fileSize() {\r
+#ifdef __linux__\r
+    return getStatus()->st_size;\r
 #elif defined __WIN32__\r
+    return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow;\r
 #endif\r
-    return buffer.str();\r
 }\r
 \r
 /**\r
@@ -88,21 +69,43 @@ const char* ReDirStatus_t::filetimeAsString(ReByteBuffer& buffer) {
     return filetimeToString(modified(), buffer);\r
 }\r
 \r
+/**\r
+ * Converts a filetime to a string.\r
+ *\r
+ * @param time         the filetime to convert\r
+ * @param buffer       OUT: the buffer for the string\r
+ * @return                     <code>buffer.str()</code>, e.g. "2014.01.07 02:59:43"\r
+ */\r
+const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer){\r
+    time_t time1 = filetimeToTime(time);\r
+    struct tm* time2 = localtime(&time1);\r
+    buffer.setLength(4+2*2+2*2+1+3*2+2*1);\r
+    strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2);\r
+       return buffer.str();\r
+}\r
 \r
 /**\r
- * Tests whether the instance contains data about "." or "..".\r
+ * Converts a filetime to a unix time (seconds since the Epoche).\r
  *\r
- * @return     <code>true</code>: an ignorable entry has been found\r
+ * @param filetime             the filetime to convert\r
+ * @return                             the count of seconds since 1.1.1970\r
  */\r
-bool ReDirStatus_t::isDotDir() const{\r
+time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){\r
 #ifdef __linux__\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
+    return filetime->tv_sec;\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
+    // 64-bit arithmetic:\r
+    LARGE_INTEGER date, adjust;\r
+    date.HighPart = filetime->dwHighDateTime;\r
+    date.LowPart = filetime->dwLowDateTime;\r
+    // 100-nanoseconds = milliseconds * 10000\r
+    adjust.QuadPart = 11644473600000 * 10000;\r
+    // removes the diff between 1970 and 1601\r
+    date.QuadPart -= adjust.QuadPart;\r
+    // converts back from 100-nanoseconds to seconds\r
+    time_t rc = (time_t) (date.QuadPart / 10000000);\r
+       return rc;\r
 #endif\r
-    return rc;\r
 }\r
 \r
 /**\r
@@ -122,7 +125,7 @@ bool ReDirStatus_t::findFirst(){
        if (m_handle != INVALID_HANDLE_VALUE)\r
                FindClose(m_handle);\r
        ReByteBuffer thePath(m_path);\r
-       thePath.append(m_path.str()[m_path.length() - 1] == '\\' ? "*" : "\\*");\r
+       thePath.append(m_path.lastChar() == '\\' ? "*" : "\\*");\r
        m_handle = FindFirstFileA(thePath.str(), &m_data);\r
        rc = m_handle != INVALID_HANDLE_VALUE;\r
 #endif\r
@@ -147,53 +150,22 @@ bool ReDirStatus_t::findNext(){
 }\r
 \r
 /**\r
- * Returns the type of the entry.\r
- * return       the file type, e.g. TF_REGULAR\r
+ * Frees the resources of an instance.\r
  */\r
-ReDirStatus_t::Type_t ReDirStatus_t::type(){\r
-    Type_t rc = TF_UNDEF;\r
+void ReDirStatus_t::freeEntry(){\r
 #if defined __linux__\r
-       int flags = m_status.st_mode;\r
-    if (flags == 0 || S_ISREG(flags))\r
-        rc = TF_REGULAR;\r
-    else if (S_ISDIR(flags)){\r
-        rc = TF_SUBDIR;\r
-    } else if (S_ISLNK(flags))\r
-        rc = TF_LINK;\r
-    else if (S_ISCHR(flags))\r
-        rc = TF_CHAR;\r
-    else if (S_ISBLK(flags))\r
-        rc = TF_BLOCK;\r
-    else if (S_ISFIFO(flags))\r
-        rc = TF_PIPE;\r
-    else if (S_ISSOCK(flags))\r
-        rc = TF_SOCKET;\r
-    else\r
-        rc = TF_OTHER;\r
+       if (m_handle != NULL){\r
+               closedir(m_handle);\r
+               m_handle = NULL;\r
+       }\r
 #elif defined __WIN32__\r
-    int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY\r
-        | FILE_ATTRIBUTE_HIDDEN  \r
-        | FILE_ATTRIBUTE_SYSTEM  \r
-        | FILE_ATTRIBUTE_ARCHIVE  \r
-        | FILE_ATTRIBUTE_NORMAL\r
-        | FILE_ATTRIBUTE_TEMPORARY  \r
-        | FILE_ATTRIBUTE_SPARSE_FILE  \r
-        | FILE_ATTRIBUTE_COMPRESSED  \r
-        | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  \r
-        | FILE_ATTRIBUTE_ENCRYPTED  \r
-        | FILE_ATTRIBUTE_HIDDEN));\r
-\r
-    if (0 == flags)\r
-        rc = TF_REGULAR;\r
-    else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){\r
-        rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
-            ? TF_LINK_DIR : TF_SUBDIR;\r
-    } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
-        rc = TF_LINK;\r
-    else\r
-        rc = TF_OTHER;\r
+       if (m_handle != INVALID_HANDLE_VALUE){\r
+               FindClose(m_handle);\r
+               m_handle = INVALID_HANDLE_VALUE;\r
+       }\r
 #endif\r
-    return rc;\r
+       m_path.setLength(0);\r
+       m_fullName.setLength(0);\r
 }\r
 \r
 /**\r
@@ -206,6 +178,7 @@ const char* ReDirStatus_t::fullName(){
                m_fullName.set(m_path).append(node(), -1);\r
        return m_fullName.str();\r
 }\r
+\r
 /**\r
  * Tests whether the instance is a directory.\r
  *\r
@@ -219,6 +192,23 @@ bool ReDirStatus_t::isDirectory() {
     return 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
 #endif\r
 }\r
+\r
+/**\r
+ * Tests whether the instance contains data about "." or "..".\r
+ *\r
+ * @return     <code>true</code>: an ignorable entry has been found\r
+ */\r
+bool ReDirStatus_t::isDotDir() const{\r
+#ifdef __linux__\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
+#endif\r
+    return rc;\r
+}\r
+\r
 /**\r
  * Tests whether the instance is a symbolic link.\r
  *\r
@@ -249,18 +239,6 @@ bool ReDirStatus_t::isRegular() {
     return 0 == (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));\r
 #endif\r
 }\r
-/**\r
- * Returns the filesize.\r
- *\r
- * @return     the filesize\r
- */\r
-ReFileSize_t ReDirStatus_t::fileSize() {\r
-#ifdef __linux__\r
-    return getStatus()->st_size;\r
-#elif defined __WIN32__\r
-    return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow;\r
-#endif\r
-}\r
 /**\r
  * Returns the modification time.\r
  *\r
@@ -275,56 +253,96 @@ const ReFileTime_t* ReDirStatus_t::modified() {
 }\r
 \r
 /**\r
- * Returns the last access time.\r
+ * Returns the name of the current file (without path).\r
  *\r
- * @return     the last access time\r
+ * @return     the name of the current file.\r
  */\r
-const ReFileTime_t* ReDirStatus_t::accessed() {\r
+const char* ReDirStatus_t::node() const{\r
 #ifdef __linux__\r
-    return &(getStatus()->st_atim);\r
+    return m_data->d_name;\r
 #elif defined __WIN32__\r
-    return &m_data.ftLastAccessTime;\r
+    return m_data.cFileName;\r
 #endif\r
 }\r
 \r
-/**\r
- * Converts a filetime to a string.\r
- *\r
- * @param time         the filetime to convert\r
- * @param buffer       OUT: the buffer for the string\r
- * @return                     <code>buffer.str()</code>, e.g. "2014.01.07 02:59:43"\r
- */\r
-const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer){\r
-    time_t time1 = filetimeToTime(time);\r
-    struct tm* time2 = localtime(&time1);\r
-    buffer.setLength(4+2*2+2*2+1+3*2+2*1);\r
-    strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2);\r
-       return buffer.str();\r
+inline void addRight(int mode, ReByteBuffer& buffer){\r
+       char right;\r
+       switch(mode & 7){\r
+               case 1:\r
+                       right = 'x';\r
+                       break;\r
+               case 2:\r
+                       right = 'w';\r
+                       break;\r
+               case 3:\r
+                       right = 'X';\r
+                       break;\r
+               case 4:\r
+                       right = 'r';\r
+                       break;\r
+               case 5:\r
+                       right = 'R';\r
+                       break;\r
+               case 6:\r
+                       right = 'W';\r
+                       break;\r
+               case 7:\r
+                       right = 'A';\r
+                       break;\r
+               default:\r
+                       right = '-';\r
+                       break;\r
+       }\r
+       buffer.appendChar(right);\r
+}\r
+inline void addId(const char* id, int maxLength, ReByteBuffer& buffer){\r
+       int length = strlen(id);\r
+       if (length == maxLength)\r
+               buffer.append(id, length);\r
+       else if (length < maxLength)\r
+               buffer.append(id, length).appendChar(' ', maxLength - length);\r
+       else {\r
+               buffer.append(id, 2);\r
+               buffer.append(id + length - maxLength - 2, maxLength - 2);\r
+       }\r
 }\r
-\r
 /**\r
- * Converts a filetime to a unix time (seconds since the Epoche).\r
+ * Returns the file rights as a string.\r
  *\r
- * @param filetime             the filetime to convert\r
- * @return                             the count of seconds since 1.1.1970\r
+ * @param buffer    OUT: the file rights\r
+ * @return          <code>buffer.str()</code> (for chaining)\r
  */\r
-time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){\r
-#ifdef __linux__\r
-    return filetime->tv_sec;\r
+const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer, bool numerical) {\r
+    buffer.setLength(0);\r
+#if defined __linux__\r
+       if (numerical){\r
+               buffer.appendInt(getStatus()->st_mode & ALLPERMS, "%04o");\r
+               buffer.appendInt(getStatus()->st_uid, " %4d");\r
+               buffer.appendInt(getStatus()->st_gid, " %4d");\r
+       } else {\r
+               int mode = getStatus()->st_mode & ALLPERMS;\r
+               addRight(mode >> 6, buffer);\r
+               addRight(mode >> 3, buffer);\r
+               addRight(mode, buffer);\r
+               buffer.appendChar(' ');\r
+               struct passwd* passwd = getpwuid(getStatus()->st_uid);\r
+               if (passwd == NULL)\r
+                       buffer.appendInt(getStatus()->st_uid, "%4d");\r
+               else\r
+                       addId(passwd->pw_name, 5, buffer);\r
+               buffer.appendChar(' ');\r
+               struct group* group = getgrgid(getStatus()->st_gid);\r
+               if (group == NULL)\r
+                       buffer.appendInt(getStatus()->st_gid, "%4d");\r
+               else\r
+                       addId(group->gr_name, 5, buffer);\r
+               buffer.appendChar(' ');\r
+       }\r
 #elif defined __WIN32__\r
-    // 64-bit arithmetic:\r
-    LARGE_INTEGER date, adjust;\r
-    date.HighPart = filetime->dwHighDateTime;\r
-    date.LowPart = filetime->dwLowDateTime;\r
-    // 100-nanoseconds = milliseconds * 10000\r
-    adjust.QuadPart = 11644473600000 * 10000;\r
-    // removes the diff between 1970 and 1601\r
-    date.QuadPart -= adjust.QuadPart;\r
-    // converts back from 100-nanoseconds to seconds\r
-    time_t rc = (time_t) (date.QuadPart / 10000000);\r
-       return rc;\r
 #endif\r
+    return buffer.str();\r
 }\r
+\r
 /**\r
  * Converts the unix time (time_t) to the file time.\r
  *\r
@@ -341,7 +359,91 @@ void  ReDirStatus_t::timeToFiletime(time_t time, ReFileTime_t& filetime){
     filetime.dwHighDateTime = ll >> 32;\r
 #endif\r
 }\r
+/**\r
+ * Returns the type of the entry.\r
+ * return       the file type, e.g. TF_REGULAR\r
+ */\r
+ReDirStatus_t::Type_t ReDirStatus_t::type(){\r
+    Type_t rc = TF_UNDEF;\r
+#if defined __linux__\r
+       int flags = getStatus()->st_mode;\r
+    if (S_ISDIR(flags))\r
+        rc = TF_SUBDIR;\r
+    else if (flags == 0 || S_ISREG(flags))\r
+        rc = TF_REGULAR;\r
+    else if (S_ISLNK(flags))\r
+        rc = TF_LINK;\r
+    else if (S_ISCHR(flags))\r
+        rc = TF_CHAR;\r
+    else if (S_ISBLK(flags))\r
+        rc = TF_BLOCK;\r
+    else if (S_ISFIFO(flags))\r
+        rc = TF_PIPE;\r
+    else if (S_ISSOCK(flags))\r
+        rc = TF_SOCKET;\r
+    else\r
+        rc = TF_OTHER;\r
+#elif defined __WIN32__\r
+    int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY\r
+        | FILE_ATTRIBUTE_HIDDEN\r
+        | FILE_ATTRIBUTE_SYSTEM\r
+        | FILE_ATTRIBUTE_ARCHIVE\r
+        | FILE_ATTRIBUTE_NORMAL\r
+        | FILE_ATTRIBUTE_TEMPORARY\r
+        | FILE_ATTRIBUTE_SPARSE_FILE\r
+        | FILE_ATTRIBUTE_COMPRESSED\r
+        | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED\r
+        | FILE_ATTRIBUTE_ENCRYPTED\r
+        | FILE_ATTRIBUTE_HIDDEN));\r
+\r
+    if (0 == flags)\r
+        rc = TF_REGULAR;\r
+    else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){\r
+        rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
+            ? TF_LINK_DIR : TF_SUBDIR;\r
+    } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
+        rc = TF_LINK;\r
+    else\r
+        rc = TF_OTHER;\r
+#endif\r
+    return rc;\r
+}\r
 \r
+/**\r
+ * Returns the filetype as a single character.\r
+ *\r
+ * @return     the filetype, e.g. 'd' for a directory\r
+ */\r
+char ReDirStatus_t::typeAsChar(){\r
+       char rc = ' ';\r
+       switch(type()){\r
+               case TF_REGULAR:\r
+                       rc = ' ';\r
+                       break;\r
+               case TF_LINK:\r
+                       rc = 'l';\r
+                       break;\r
+               case TF_SUBDIR:\r
+                       rc = 'd';\r
+                       break;\r
+               case TF_CHAR:\r
+                       rc = 'c';\r
+                       break;\r
+               case TF_BLOCK:\r
+                       rc = 'b';\r
+                       break;\r
+               case TF_PIPE:\r
+                       rc = 'p';\r
+                       break;\r
+               case TF_SOCKET:\r
+                       rc = 's';\r
+                       break;\r
+               default:\r
+                       rc = 'o';\r
+                       break;\r
+       }\r
+       return rc;\r
+}\r
 /**\r
  * Constructor.\r
  */\r
@@ -431,9 +533,9 @@ const char* ReDirTreeStatistic::statisticAsString(ReByteBuffer& buffer, bool app
        if (! append)\r
                buffer.setLength(0);\r
        buffer.appendInt(m_files, formatFiles);\r
-       buffer.append(i18n("file(s)")).append(" ", 1);\r
+       buffer.append(i18n("file(s)")).appendChar(' ');\r
        buffer.append(m_sizes / 1000.0 / 1000, formatSizes);\r
-       buffer.append(" ", 1).append(i18n("MByte")).append(" ", 1);\r
+       buffer.append(" ", 1).append(i18n("MByte")).appendChar(' ');\r
        buffer.appendInt(m_directories, formatDirs);\r
        buffer.append(i18n("dirs(s)"));\r
        return buffer.str();\r
@@ -492,7 +594,7 @@ ReTraverser::ReTraverser(const char* base, ReTraceUnit* tracer) :
        memset(m_dirs, 0, sizeof m_dirs);\r
        m_dirs[0] = new ReDirStatus_t();\r
        // remove a preceeding "./". This simplifies the pattern expressions:\r
-       if (m_base.startsWith(ReByteBuffer(".").append(OS_SEPARATOR, 1).str())){\r
+       if (m_base.startsWith(ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())){\r
                m_base.remove(0, 2);\r
        }\r
 }\r
@@ -515,7 +617,7 @@ void ReTraverser::changeBase(const char* base){
        memset(m_dirs, 0, sizeof m_dirs);\r
        m_dirs[0] = new ReDirStatus_t();\r
        // remove a preceeding "./". This simplifies the pattern expressions:\r
-       if (m_base.startsWith(ReByteBuffer(".").append(OS_SEPARATOR, 1).str())){\r
+       if (m_base.startsWith(ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())){\r
                m_base.remove(0, 2);\r
        }\r
 }\r
index 8606b0a1c9af72495799a9f9ad3b9e7dc43decc4..41d87695905d680cde6ef429fadfc373480cb81f 100644 (file)
@@ -62,22 +62,26 @@ public:
 public:
        ReDirStatus_t();
 public:
-       void freeEntry();
-    const char* node() const;
-       const char* fullName();
+    const ReFileTime_t* accessed();
+    ReFileSize_t fileSize();
+    const char* filetimeAsString(ReByteBuffer& buffer);
     bool findFirst();
     bool findNext();
-    bool hasData() const;
+       void freeEntry();
+       const char* fullName();
     bool isDirectory();
+    bool isDotDir() const;
     bool isLink();
     bool isRegular();
-    ReFileSize_t fileSize();
     const ReFileTime_t* modified();
-    const ReFileTime_t* accessed();
-    bool isDotDir() const;
-    const char* rightsAsString(ReByteBuffer& buffer);
-    const char* filetimeAsString(ReByteBuffer& buffer);
+    const char* node() const;
+    const char* rightsAsString(ReByteBuffer& buffer, bool numerical);
     Type_t type(); 
+       char typeAsChar();
+public:
+    static time_t filetimeToTime(const ReFileTime_t* time);
+    static void timeToFiletime(time_t time, ReFileTime_t& filetime);
+    static const char* filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer);
 public:
        ReByteBuffer m_path;
        ReByteBuffer m_fullName;
@@ -92,10 +96,6 @@ public:
        HANDLE m_handle;
        WIN32_FIND_DATAA m_data;
 #endif
-public:
-    static time_t filetimeToTime(const ReFileTime_t* time);
-    static void timeToFiletime(time_t time, ReFileTime_t& filetime);
-    static const char* filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer);
 };
 class ReDirEntryFilter_t{
 public:
index 74083daf929850769d39eb51418ad522266e5ea8..0b1dbb201093a71235d463102f7a3520519a58a0 100644 (file)
@@ -13,6 +13,8 @@
 #if defined __linux__
 #include "unistd.h"
 #include <dirent.h>
+#include <grp.h>
+#include <pwd.h>
 #elif defined __WIN32__
 #include <tchar.h>
 #include "windows.h"