From: hama Date: Sun, 22 Feb 2015 23:24:27 +0000 (+0100) Subject: bug fixing X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=5ebd0339e1259102f61d64d8851881efca43b87b;p=crepublib bug fixing --- diff --git a/base/ReByteBuffer.cpp b/base/ReByteBuffer.cpp index f12c8d2..06e6c3e 100644 --- a/base/ReByteBuffer.cpp +++ b/base/ReByteBuffer.cpp @@ -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; diff --git a/base/ReByteBuffer.hpp b/base/ReByteBuffer.hpp index 69feda2..590dbce 100644 --- a/base/ReByteBuffer.hpp +++ b/base/ReByteBuffer.hpp @@ -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 *this (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 *this (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 *this (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 true: 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
+ * 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 *this (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 < 0: relative to the end. diff --git a/base/ReDirectory.cpp b/base/ReDirectory.cpp index 1982c94..64fe2e0 100644 --- a/base/ReDirectory.cpp +++ b/base/ReDirectory.cpp @@ -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. diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp index 701a742..139a9d6 100644 --- a/base/ReProgramArgs.cpp +++ b/base/ReProgramArgs.cpp @@ -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()); diff --git a/base/ReTestUnit.cpp b/base/ReTestUnit.cpp index 9d89d5c..7797d2f 100644 --- a/base/ReTestUnit.cpp +++ b/base/ReTestUnit.cpp @@ -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(); } diff --git a/base/ReVarArgs.cpp b/base/ReVarArgs.cpp index 77f2474..4188be4 100644 --- a/base/ReVarArgs.cpp +++ b/base/ReVarArgs.cpp @@ -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); } diff --git a/base/rebase.hpp b/base/rebase.hpp index 1a8407c..d9bfbbe 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -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__ diff --git a/cunit/cuReByteBuffer.cpp b/cunit/cuReByteBuffer.cpp index b4fe8be..3bb497a 100644 --- a/cunit/cuReByteBuffer.cpp +++ b/cunit/cuReByteBuffer.cpp @@ -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; diff --git a/cunit/cuReDirTools.cpp b/cunit/cuReDirTools.cpp index 60d47e2..16ffc99 100644 --- a/cunit/cuReDirTools.cpp +++ b/cunit/cuReDirTools.cpp @@ -11,15 +11,19 @@ #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" }; diff --git a/cunit/cuReHashList.cpp b/cunit/cuReHashList.cpp index 6990a6e..f6820ba 100644 --- a/cunit/cuReHashList.cpp +++ b/cunit/cuReHashList.cpp @@ -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); } diff --git a/cunit/cuReSeqArray.cpp b/cunit/cuReSeqArray.cpp index 20bda85..8d5fe54 100644 --- a/cunit/cuReSeqArray.cpp +++ b/cunit/cuReSeqArray.cpp @@ -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)); diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp index 0d21f1f..8d96896 100644 --- a/cunit/cuReTraverser.cpp +++ b/cunit/cuReTraverser.cpp @@ -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; diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index 32b34b6..ceb6019 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -299,15 +299,17 @@ ReFileTime_t ReDirOptions::checkDate(const char* value){ // a time distance value: char unit = 'm'; int count = 0; - int isNegative = false; - if (theValue.startsWith("now")){ - rcTime = time(NULL); + bool negativeFactor = 1; + bool fromNow = theValue.startsWith("now"); + if (fromNow){ theValue.remove(0, 3); } - if (theValue.str()[0] == '-') - isNegative = true; - else if (theValue.startsWith("+")) + char cc = theValue.at(0); + if (cc == '-' || cc == '+'){ + if (cc == '-') + negativeFactor = -1; theValue.remove(0, 1); + } switch(sscanf(theValue.str(), "%d%c", &count, &unit)){ case 1: case 2: @@ -327,17 +329,15 @@ ReFileTime_t ReDirOptions::checkDate(const char* value){ throw ReOptionException(&m_programArgs, i18n("invalid unit $1. expected: s(econds) m(inutes) h(ours) d(ays)"), value); } - rcTime = time(NULL) - count; + rcTime = count * negativeFactor; break; default: throw ReOptionException(&m_programArgs, i18n("invalid relative time value $1 ( expected). : s m h d"), value); } - if (isNegative) - rcTime -= count; - else - rcTime += count; + if (fromNow) + rcTime += time(NULL); } ReFileTime_t rc; ReDirStatus_t::timeToFiletime(rcTime, rc); @@ -524,10 +524,10 @@ void ReDirOptions::checkStandardFilterOptions(){ * Frees the resources. */ void ReDirOptions::close(){ - if (m_output != stdout){ + if (m_output != stdout && m_output != stderr){ fclose(m_output); - m_output = stdout; } + m_output = stdout; } /** @@ -564,8 +564,7 @@ void ReDirOptions::optimizePathPattern(ReByteBuffer& buffer){ item.set(list.strOf(ix), -1); if (item.endsWith("/*")) item.setLength(item.length() - 2); - if (item.endsWith("/")) - item.setLength(item.length() - 1); + item.removeLastChar('/'); bool notAnchored = item.startsWith("*/") || item.startsWith("-*/"); item.replaceAll("/", 1, OS_SEPARATOR, 1); list.replace(ix, item.str()); @@ -666,8 +665,8 @@ bool ReTool::trace(const char* currentFile){ ReByteBuffer buffer(" "); int duration = int(time(NULL) - m_startTime); buffer.appendInt(duration / 60).appendInt(duration % 60, ":%02d: "); - buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.directories()).append(" dir(s)"); - buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.files()).append(" file(s)"); + buffer.appendInt(m_files).appendChar('/').appendInt(m_traverser.directories()).append(" dir(s)"); + buffer.appendInt(m_files).appendChar('/').appendInt(m_traverser.files()).append(" file(s)"); buffer.append(currentFile); fputs(buffer.str(), stdout); return true; @@ -734,7 +733,7 @@ void ReTool::processSingleFile(const char* filename){ if (protocol.length() == 0) protocol.append("."); else - protocol.setLength(protocol.length() - 1); + protocol.reduceLength(); m_traverser.changeBase(protocol.str()); name.append(ext); @@ -806,7 +805,7 @@ void ReTool::printSummary(const char* prefix){ double rate = duration == 0 ? 0.0 : (m_files + m_directories) / duration; line.append(rate, " %.1f").append(i18n("/sec"), -1); m_traverser.statisticAsString(line2); - line2.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec")); + line2.appendChar(' ').appendTime(duration).append(" ", 1).append(i18n("sec")); fprintf(m_output, "%s=== filtered: %s\n", prefix == NULL ? "" : prefix, line.str()); fprintf(m_output, "%s=== total: %s\n", prefix == NULL ? "" : prefix, line2.str()); } @@ -899,7 +898,8 @@ ReDirBatch::ReDirBatch() : ReTool(s_batchUsage, s_batchExamples, 0, 0, 0, true), m_arguments(), m_script(), - m_isExe(false) + m_isExe(false), + m_first() { // standard short options: D d O o P p T t v y Z z m_programArgs.addString("first", @@ -973,7 +973,7 @@ static void replaceMakros(const char* arguments, ReDirStatus_t* entry, const cha } // We remove the unwanted delimiters (see above): ReByteBuffer buffer; - buffer.set(delim, -1).append("\x01", 1).append(delim, -1); + buffer.set(delim, -1).appendChar('\01').append(delim, -1); line.replaceAll(buffer.str(), buffer.length(), "", 0); } /** @@ -981,25 +981,21 @@ static void replaceMakros(const char* arguments, ReDirStatus_t* entry, const cha */ void ReDirBatch::doIt(){ ReByteBuffer buffer; - m_arguments.append(m_programArgs.getString("arguments", buffer), -1); - m_script.append(m_programArgs.getString("script", buffer), -1); + m_programArgs.getString("arguments", m_arguments); + m_programArgs.getString("script", m_script); if (m_arguments.length() + m_script.length() == 0) help(i18n("one of the option must be set: -a (--arguments) or -c (--script)")); #if defined __WIN32__ m_isExe = m_programArgs.getBool("isexe"); #endif + m_programArgs.getString("first", m_first); processFileArguments(); - if (m_verboseLevel >= V_SUMMARY){ - int duration = int(time(NULL) - m_start); #if defined __linux__ - const char* prefix = "#"; + static const char* prefix = "# "; #elif defined __WIN32__ - const char* prefix = "rem"; + static const char* prefix = "rem "; #endif - statisticAsString(buffer); - buffer.append(" ").appendTime(duration); - fprintf(m_output, "%s %s\n", buffer.str()); - } + printSummary(prefix); } /** @@ -1023,14 +1019,18 @@ void ReDirBatch::processFile(ReDirStatus_t* entry){ #elif defined __WIN32__ static const char* delim = "\""; #endif + if (m_first.length() > 0){ + fprintf(m_output, "%s\n", m_first.str()); + m_first.setLength(0); + } if (m_script.length() > 0){ #if defined __WIN32__ if (! m_isExe) line.append("call "); #endif - line.append(m_script).append(" ").append(delim, -1); + line.append(m_script).appendChar(' ').appendChar(delim[0]); line.append(entry->m_path).append(entry->node(), -1); - line.append(delim, -1); + line.appendChar(delim[0]); } else { replaceMakros(m_arguments.str(), entry, delim, line); } @@ -1042,10 +1042,17 @@ void ReDirBatch::processFile(ReDirStatus_t* entry){ */ ReDirList::ReDirList() : ReTool(s_listUsage, s_listExamples, 0, 0, 0, true), - m_shortFormat(false) + m_shortFormat(false), + m_hideRights(false), + m_numerical(false) { + // standard short options: D d O o P p T t v y Z z m_programArgs.addBool("short", i18n("output is only path and basename"), '1', "--short", false); + m_programArgs.addBool("rights", i18n("do not show the permission/right info"), + 'h', "--hide-rights", false); + m_programArgs.addBool("numerical", i18n("the permission/right info is shown as numbers"), + 'n', "--numerical", false); addStandardFilterOptions(); } @@ -1054,14 +1061,10 @@ ReDirList::ReDirList() : */ void ReDirList::doIt(){ m_shortFormat = m_programArgs.getBool("short"); + m_hideRights = m_programArgs.getBool("rights"); + m_numerical = m_programArgs.getBool("numerical"); processFileArguments(); - if (m_verboseLevel >= V_SUMMARY){ - int duration = int(time(NULL) - m_start); - ReByteBuffer line; - statisticAsString(line); - line.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec")); - fprintf(m_output, "=== %s\n", line.str()); - } + printSummary(); } /** @@ -1082,13 +1085,16 @@ void ReDirList::processFile(ReDirStatus_t* entry){ ReByteBuffer bufferTime; if (m_shortFormat) fprintf(m_output, "%s%s\n", entry->m_path.str(), entry->node()); - else - fprintf(m_output, "%s %12.6f %s %02x %s%s\n", - entry->rightsAsString(bufferRights), + else { + if (! m_hideRights) + entry->rightsAsString(bufferRights, m_numerical); + fprintf(m_output, "%c%s %12.6f %s %s%s\n", + entry->typeAsChar(), + bufferRights.str(), entry->fileSize() / 1E6, entry->filetimeAsString(bufferTime), - entry->type(), entry->m_path.str(), entry->node()); + } } @@ -1666,13 +1672,12 @@ bool ReDirSync::makeDirectory(const char* directory, int minLength, #if defined __WIN32__ start = path.indexOf(':'); #endif + path.ensureLastChar(OS_SEPARATOR_CHAR); int ixSlash = start < 0 ? 0 : start; struct stat info; // for all parents and the full path itself: while(ixSlash >= 0){ ixSlash = path.indexOf(OS_SEPARATOR_CHAR, ixSlash + 1); - if (ixSlash >= (int) path.length() - 1) - break; // is the slash in front of the first node, e.g. 'e:\'? if (ixSlash == start + 1) // not a real node: take the next node @@ -1713,8 +1718,7 @@ void ReDirSync::doIt(){ const char* sep = OS_SEPARATOR; ReByteBuffer buffer; ReByteBuffer target(m_programArgs.getArg(m_programArgs.getArgCount() - 1)); - if (target.endsWith(OS_SEPARATOR)) - target.setLength(target.length() - 1); + target.removeLastChar(OS_SEPARATOR_CHAR); if (! exists(target)) help(i18n("target does not exist: $1"), target.str()); else if (! S_ISDIR(m_statInfo.st_mode)) @@ -1737,7 +1741,7 @@ void ReDirSync::doIt(){ target.setLength(lengthTargetBase); bool endsWithSlash = source.endsWith(sep, 1); if (endsWithSlash) - source.setLength(source.length() - 1); + source.reduceLength(); if (! exists(source)) help(i18n("source does not exist: $1"), source.str()); else if (! S_ISDIR(m_statInfo.st_mode)) @@ -1745,25 +1749,25 @@ void ReDirSync::doIt(){ if (! endsWithSlash){ // the basename of the source will be appended to the target: int startNode = source.rindexOf(sep, 1, 0, source.length() - 1); - target.append(OS_SEPARATOR, 1); + target.appendChar(OS_SEPARATOR_CHAR); target.append(source.str() + startNode + 1, -1); } size_t ixSourceRelative = source.length(); size_t ixTargetRelative = target.length(); - ReTraverser traverser(source.str()); - traverser.setPropertiesFromFilter(&filter); + m_traverser.changeBase(source.str()); + m_traverser.setPropertiesFromFilter(&filter); int level; ReDirStatus_t* entry; ReByteBuffer line; - while( (entry = traverser.nextFile(level, &filter)) != NULL){ + while( (entry = m_traverser.nextFile(level, &filter)) != NULL){ if (entry->isDirectory()) continue; // append the new relative path from source to target: target.setLength(ixTargetRelative); target.append(entry->m_path.str() + ixSourceRelative, -1); if (! exists(target)) - makeDirWithParents(target, ixTargetRelative, traverser); + makeDirWithParents(target, ixTargetRelative, m_traverser); targetFile.set(target).append(entry->node(), -1); const char* targetRelativePath = targetFile.str() + ixTargetRelative + 1; bool targetExists = exists(targetFile); @@ -1800,9 +1804,9 @@ void ReDirSync::doIt(){ if (! dry) copyFile(entry, targetFile.str()); } - treeFiles += traverser.files(); - treeDirs += traverser.directories(); - treeSumSizes+= traverser.sizes(); + treeFiles += m_traverser.files(); + treeDirs += m_traverser.directories(); + treeSumSizes+= m_traverser.sizes(); } if (m_verboseLevel >= V_SUMMARY){ int duration = int(time(NULL) - m_start); @@ -1902,7 +1906,6 @@ int ReDirTools::main(int argc, char* orgArgv[]){ testAll(); }else tools.usage("unknown command: ", argv[1]); - ReLogger::freeGlobalLogger(); return 0; } diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 2fcf836..8985ec6 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -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; }; /** diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index 20e8d14..6c96df6 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -34,48 +34,29 @@ ReDirStatus_t::ReDirStatus_t() : } /** - * Frees the resources of an instance. - */ -void ReDirStatus_t::freeEntry(){ -#if defined __linux__ - if (m_handle != NULL){ - closedir(m_handle); - m_handle = NULL; - } -#elif defined __WIN32__ - if (m_handle != INVALID_HANDLE_VALUE){ - FindClose(m_handle); - m_handle = INVALID_HANDLE_VALUE; - } -#endif - m_path.setLength(0); - m_fullName.setLength(0); -} - -/** - * Returns the name of the current file (without path). + * Returns the last access time. * - * @return the name of the current file. + * @return the last access time */ -const char* ReDirStatus_t::node() const{ +const ReFileTime_t* ReDirStatus_t::accessed() { #ifdef __linux__ - return m_data->d_name; + return &(getStatus()->st_atim); #elif defined __WIN32__ - return m_data.cFileName; + return &m_data.ftLastAccessTime; #endif } + /** - * Returns the file rights as a string. + * Returns the filesize. * - * @param buffer OUT: the file rights - * @return buffer.str() (for chaining) + * @return the filesize */ -const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer) { - buffer.setLength(0); -#if defined __linux__ +ReFileSize_t ReDirStatus_t::fileSize() { +#ifdef __linux__ + return getStatus()->st_size; #elif defined __WIN32__ + return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow; #endif - return buffer.str(); } /** @@ -88,21 +69,43 @@ const char* ReDirStatus_t::filetimeAsString(ReByteBuffer& buffer) { return filetimeToString(modified(), buffer); } +/** + * Converts a filetime to a string. + * + * @param time the filetime to convert + * @param buffer OUT: the buffer for the string + * @return buffer.str(), e.g. "2014.01.07 02:59:43" + */ +const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer){ + time_t time1 = filetimeToTime(time); + struct tm* time2 = localtime(&time1); + buffer.setLength(4+2*2+2*2+1+3*2+2*1); + strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2); + return buffer.str(); +} /** - * Tests whether the instance contains data about "." or "..". + * Converts a filetime to a unix time (seconds since the Epoche). * - * @return true: an ignorable entry has been found + * @param filetime the filetime to convert + * @return the count of seconds since 1.1.1970 */ -bool ReDirStatus_t::isDotDir() const{ +time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){ #ifdef __linux__ - bool rc = m_data == NULL || (m_data->d_name[0] == '.' && (m_data->d_name[1] == '\0' - || (m_data->d_name[1] == '.' && m_data->d_name[2] == '\0'))); + return filetime->tv_sec; #elif defined __WIN32__ - bool rc = m_data.cFileName[0] == '.' && (m_data.cFileName[1] == '\0' - || (m_data.cFileName[1] == '.' && m_data.cFileName[2] == '\0')); + // 64-bit arithmetic: + LARGE_INTEGER date, adjust; + date.HighPart = filetime->dwHighDateTime; + date.LowPart = filetime->dwLowDateTime; + // 100-nanoseconds = milliseconds * 10000 + adjust.QuadPart = 11644473600000 * 10000; + // removes the diff between 1970 and 1601 + date.QuadPart -= adjust.QuadPart; + // converts back from 100-nanoseconds to seconds + time_t rc = (time_t) (date.QuadPart / 10000000); + return rc; #endif - return rc; } /** @@ -122,7 +125,7 @@ bool ReDirStatus_t::findFirst(){ if (m_handle != INVALID_HANDLE_VALUE) FindClose(m_handle); ReByteBuffer thePath(m_path); - thePath.append(m_path.str()[m_path.length() - 1] == '\\' ? "*" : "\\*"); + thePath.append(m_path.lastChar() == '\\' ? "*" : "\\*"); m_handle = FindFirstFileA(thePath.str(), &m_data); rc = m_handle != INVALID_HANDLE_VALUE; #endif @@ -147,53 +150,22 @@ bool ReDirStatus_t::findNext(){ } /** - * Returns the type of the entry. - * return the file type, e.g. TF_REGULAR + * Frees the resources of an instance. */ -ReDirStatus_t::Type_t ReDirStatus_t::type(){ - Type_t rc = TF_UNDEF; +void ReDirStatus_t::freeEntry(){ #if defined __linux__ - int flags = m_status.st_mode; - if (flags == 0 || S_ISREG(flags)) - rc = TF_REGULAR; - else if (S_ISDIR(flags)){ - rc = TF_SUBDIR; - } else if (S_ISLNK(flags)) - rc = TF_LINK; - else if (S_ISCHR(flags)) - rc = TF_CHAR; - else if (S_ISBLK(flags)) - rc = TF_BLOCK; - else if (S_ISFIFO(flags)) - rc = TF_PIPE; - else if (S_ISSOCK(flags)) - rc = TF_SOCKET; - else - rc = TF_OTHER; + if (m_handle != NULL){ + closedir(m_handle); + m_handle = NULL; + } #elif defined __WIN32__ - int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY - | FILE_ATTRIBUTE_HIDDEN - | FILE_ATTRIBUTE_SYSTEM - | FILE_ATTRIBUTE_ARCHIVE - | FILE_ATTRIBUTE_NORMAL - | FILE_ATTRIBUTE_TEMPORARY - | FILE_ATTRIBUTE_SPARSE_FILE - | FILE_ATTRIBUTE_COMPRESSED - | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED - | FILE_ATTRIBUTE_ENCRYPTED - | FILE_ATTRIBUTE_HIDDEN)); - - if (0 == flags) - rc = TF_REGULAR; - else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ - rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) - ? TF_LINK_DIR : TF_SUBDIR; - } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) - rc = TF_LINK; - else - rc = TF_OTHER; + if (m_handle != INVALID_HANDLE_VALUE){ + FindClose(m_handle); + m_handle = INVALID_HANDLE_VALUE; + } #endif - return rc; + m_path.setLength(0); + m_fullName.setLength(0); } /** @@ -206,6 +178,7 @@ const char* ReDirStatus_t::fullName(){ m_fullName.set(m_path).append(node(), -1); return m_fullName.str(); } + /** * Tests whether the instance is a directory. * @@ -219,6 +192,23 @@ bool ReDirStatus_t::isDirectory() { return 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); #endif } + +/** + * Tests whether the instance contains data about "." or "..". + * + * @return true: an ignorable entry has been found + */ +bool ReDirStatus_t::isDotDir() const{ +#ifdef __linux__ + bool rc = m_data == NULL || (m_data->d_name[0] == '.' && (m_data->d_name[1] == '\0' + || (m_data->d_name[1] == '.' && m_data->d_name[2] == '\0'))); +#elif defined __WIN32__ + bool rc = m_data.cFileName[0] == '.' && (m_data.cFileName[1] == '\0' + || (m_data.cFileName[1] == '.' && m_data.cFileName[2] == '\0')); +#endif + return rc; +} + /** * Tests whether the instance is a symbolic link. * @@ -249,18 +239,6 @@ bool ReDirStatus_t::isRegular() { return 0 == (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); #endif } -/** - * Returns the filesize. - * - * @return the filesize - */ -ReFileSize_t ReDirStatus_t::fileSize() { -#ifdef __linux__ - return getStatus()->st_size; -#elif defined __WIN32__ - return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow; -#endif -} /** * Returns the modification time. * @@ -275,56 +253,96 @@ const ReFileTime_t* ReDirStatus_t::modified() { } /** - * Returns the last access time. + * Returns the name of the current file (without path). * - * @return the last access time + * @return the name of the current file. */ -const ReFileTime_t* ReDirStatus_t::accessed() { +const char* ReDirStatus_t::node() const{ #ifdef __linux__ - return &(getStatus()->st_atim); + return m_data->d_name; #elif defined __WIN32__ - return &m_data.ftLastAccessTime; + return m_data.cFileName; #endif } -/** - * Converts a filetime to a string. - * - * @param time the filetime to convert - * @param buffer OUT: the buffer for the string - * @return buffer.str(), e.g. "2014.01.07 02:59:43" - */ -const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer){ - time_t time1 = filetimeToTime(time); - struct tm* time2 = localtime(&time1); - buffer.setLength(4+2*2+2*2+1+3*2+2*1); - strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2); - return buffer.str(); +inline void addRight(int mode, ReByteBuffer& buffer){ + char right; + switch(mode & 7){ + case 1: + right = 'x'; + break; + case 2: + right = 'w'; + break; + case 3: + right = 'X'; + break; + case 4: + right = 'r'; + break; + case 5: + right = 'R'; + break; + case 6: + right = 'W'; + break; + case 7: + right = 'A'; + break; + default: + right = '-'; + break; + } + buffer.appendChar(right); +} +inline void addId(const char* id, int maxLength, ReByteBuffer& buffer){ + int length = strlen(id); + if (length == maxLength) + buffer.append(id, length); + else if (length < maxLength) + buffer.append(id, length).appendChar(' ', maxLength - length); + else { + buffer.append(id, 2); + buffer.append(id + length - maxLength - 2, maxLength - 2); + } } - /** - * Converts a filetime to a unix time (seconds since the Epoche). + * Returns the file rights as a string. * - * @param filetime the filetime to convert - * @return the count of seconds since 1.1.1970 + * @param buffer OUT: the file rights + * @return buffer.str() (for chaining) */ -time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){ -#ifdef __linux__ - return filetime->tv_sec; +const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer, bool numerical) { + buffer.setLength(0); +#if defined __linux__ + if (numerical){ + buffer.appendInt(getStatus()->st_mode & ALLPERMS, "%04o"); + buffer.appendInt(getStatus()->st_uid, " %4d"); + buffer.appendInt(getStatus()->st_gid, " %4d"); + } else { + int mode = getStatus()->st_mode & ALLPERMS; + addRight(mode >> 6, buffer); + addRight(mode >> 3, buffer); + addRight(mode, buffer); + buffer.appendChar(' '); + struct passwd* passwd = getpwuid(getStatus()->st_uid); + if (passwd == NULL) + buffer.appendInt(getStatus()->st_uid, "%4d"); + else + addId(passwd->pw_name, 5, buffer); + buffer.appendChar(' '); + struct group* group = getgrgid(getStatus()->st_gid); + if (group == NULL) + buffer.appendInt(getStatus()->st_gid, "%4d"); + else + addId(group->gr_name, 5, buffer); + buffer.appendChar(' '); + } #elif defined __WIN32__ - // 64-bit arithmetic: - LARGE_INTEGER date, adjust; - date.HighPart = filetime->dwHighDateTime; - date.LowPart = filetime->dwLowDateTime; - // 100-nanoseconds = milliseconds * 10000 - adjust.QuadPart = 11644473600000 * 10000; - // removes the diff between 1970 and 1601 - date.QuadPart -= adjust.QuadPart; - // converts back from 100-nanoseconds to seconds - time_t rc = (time_t) (date.QuadPart / 10000000); - return rc; #endif + return buffer.str(); } + /** * Converts the unix time (time_t) to the file time. * @@ -341,7 +359,91 @@ void ReDirStatus_t::timeToFiletime(time_t time, ReFileTime_t& filetime){ filetime.dwHighDateTime = ll >> 32; #endif } +/** + * Returns the type of the entry. + * return the file type, e.g. TF_REGULAR + */ +ReDirStatus_t::Type_t ReDirStatus_t::type(){ + Type_t rc = TF_UNDEF; +#if defined __linux__ + int flags = getStatus()->st_mode; + if (S_ISDIR(flags)) + rc = TF_SUBDIR; + else if (flags == 0 || S_ISREG(flags)) + rc = TF_REGULAR; + else if (S_ISLNK(flags)) + rc = TF_LINK; + else if (S_ISCHR(flags)) + rc = TF_CHAR; + else if (S_ISBLK(flags)) + rc = TF_BLOCK; + else if (S_ISFIFO(flags)) + rc = TF_PIPE; + else if (S_ISSOCK(flags)) + rc = TF_SOCKET; + else + rc = TF_OTHER; +#elif defined __WIN32__ + int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY + | FILE_ATTRIBUTE_HIDDEN + | FILE_ATTRIBUTE_SYSTEM + | FILE_ATTRIBUTE_ARCHIVE + | FILE_ATTRIBUTE_NORMAL + | FILE_ATTRIBUTE_TEMPORARY + | FILE_ATTRIBUTE_SPARSE_FILE + | FILE_ATTRIBUTE_COMPRESSED + | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED + | FILE_ATTRIBUTE_ENCRYPTED + | FILE_ATTRIBUTE_HIDDEN)); + + if (0 == flags) + rc = TF_REGULAR; + else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ + rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + ? TF_LINK_DIR : TF_SUBDIR; + } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + rc = TF_LINK; + else + rc = TF_OTHER; +#endif + return rc; +} +/** + * Returns the filetype as a single character. + * + * @return the filetype, e.g. 'd' for a directory + */ +char ReDirStatus_t::typeAsChar(){ + char rc = ' '; + switch(type()){ + case TF_REGULAR: + rc = ' '; + break; + case TF_LINK: + rc = 'l'; + break; + case TF_SUBDIR: + rc = 'd'; + break; + case TF_CHAR: + rc = 'c'; + break; + case TF_BLOCK: + rc = 'b'; + break; + case TF_PIPE: + rc = 'p'; + break; + case TF_SOCKET: + rc = 's'; + break; + default: + rc = 'o'; + break; + } + return rc; +} /** * Constructor. */ @@ -431,9 +533,9 @@ const char* ReDirTreeStatistic::statisticAsString(ReByteBuffer& buffer, bool app if (! append) buffer.setLength(0); buffer.appendInt(m_files, formatFiles); - buffer.append(i18n("file(s)")).append(" ", 1); + buffer.append(i18n("file(s)")).appendChar(' '); buffer.append(m_sizes / 1000.0 / 1000, formatSizes); - buffer.append(" ", 1).append(i18n("MByte")).append(" ", 1); + buffer.append(" ", 1).append(i18n("MByte")).appendChar(' '); buffer.appendInt(m_directories, formatDirs); buffer.append(i18n("dirs(s)")); return buffer.str(); @@ -492,7 +594,7 @@ ReTraverser::ReTraverser(const char* base, ReTraceUnit* tracer) : memset(m_dirs, 0, sizeof m_dirs); m_dirs[0] = new ReDirStatus_t(); // remove a preceeding "./". This simplifies the pattern expressions: - if (m_base.startsWith(ReByteBuffer(".").append(OS_SEPARATOR, 1).str())){ + if (m_base.startsWith(ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())){ m_base.remove(0, 2); } } @@ -515,7 +617,7 @@ void ReTraverser::changeBase(const char* base){ memset(m_dirs, 0, sizeof m_dirs); m_dirs[0] = new ReDirStatus_t(); // remove a preceeding "./". This simplifies the pattern expressions: - if (m_base.startsWith(ReByteBuffer(".").append(OS_SEPARATOR, 1).str())){ + if (m_base.startsWith(ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())){ m_base.remove(0, 2); } } diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp index 8606b0a..41d8769 100644 --- a/os/ReTraverser.hpp +++ b/os/ReTraverser.hpp @@ -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: diff --git a/os/reos.hpp b/os/reos.hpp index 74083da..0b1dbb2 100644 --- a/os/reos.hpp +++ b/os/reos.hpp @@ -13,6 +13,8 @@ #if defined __linux__ #include "unistd.h" #include +#include +#include #elif defined __WIN32__ #include #include "windows.h"