From 90cca5179a1bd7b5a47c157093f2f168f43cd665 Mon Sep 17 00:00:00 2001 From: hama Date: Mon, 6 Apr 2015 03:41:50 +0200 Subject: [PATCH] allTests works, ReUnitParser works --- appl/{qfilesearch => refind} | 0 base/ReContainer.cpp | 5 +- base/ReQString.cpp | 180 ---- base/ReQStringUtil.cpp | 360 +++++++ base/{ReQtring.hpp => ReQStringUtil.hpp} | 35 +- base/ReTerminator.hpp | 2 +- base/ReTest.cpp | 28 +- base/ReTest.hpp | 4 +- base/rebase.hpp | 13 +- base/testrplexample.cpp | 4 +- cunit/allTests.cpp | 81 ++ cunit/{rplastree_test.cpp => cuReASTree.cpp} | 6 +- cunit/{rplbench.cpp => cuReBench.cpp} | 5 +- ...testorage_test.cpp => cuReByteStorage.cpp} | 20 +- ...charptrmap_test.cpp => cuReCharPtrMap.cpp} | 9 +- cunit/cuReConfig.cpp | 1 + cunit/cuReContainer.cpp | 10 +- cunit/cuReEnigma.cpp | 8 +- ...plexception_test.cpp => cuReException.cpp} | 15 +- cunit/{rpllexer_test.cpp => cuReLexer.cpp} | 7 +- ...{rplmfparser_test.cpp => cuReMFParser.cpp} | 15 +- cunit/{rplmatrix_test.cpp => cuReMatrix.cpp} | 10 +- cunit/cuReQStringUtil.cpp | 151 +++ cunit/{rplsource_test.cpp => cuReSource.cpp} | 8 +- ...{rplstring_test.cpp => cuReStringUtil.cpp} | 30 +- cunit/cuReTraverser.cpp | 155 +++ cunit/{rplvm_test.cpp => cuReVM.cpp} | 7 +- cunit/{rplwriter_test.cpp => cuReWriter.cpp} | 14 +- cunit/main.cpp | 85 -- cunit/rplqstring_test.cpp | 128 --- expr/ReLexer.cpp | 4 +- net/ReTCPClient.hpp | 7 + net/ReTCPPeer.hpp | 6 + net/ReTCPServer.hpp | 8 +- os/ReTraverser.cpp | 989 ++++++++++++++++++ os/ReTraverser.hpp | 290 +++++ os/reos.hpp | 48 + remodules.hpp | 3 +- static/{rplstaticlib.cpp => ReStaticLib.cpp} | 10 +- static/rplstatic.pro | 38 +- static/rplstaticlib.hpp | 24 - 41 files changed, 2266 insertions(+), 557 deletions(-) rename appl/{qfilesearch => refind} (100%) delete mode 100644 base/ReQString.cpp create mode 100644 base/ReQStringUtil.cpp rename base/{ReQtring.hpp => ReQStringUtil.hpp} (61%) create mode 100644 cunit/allTests.cpp rename cunit/{rplastree_test.cpp => cuReASTree.cpp} (97%) rename cunit/{rplbench.cpp => cuReBench.cpp} (96%) rename cunit/{rplbytestorage_test.cpp => cuReByteStorage.cpp} (86%) rename cunit/{rplcharptrmap_test.cpp => cuReCharPtrMap.cpp} (89%) rename cunit/{rplexception_test.cpp => cuReException.cpp} (84%) rename cunit/{rpllexer_test.cpp => cuReLexer.cpp} (99%) rename cunit/{rplmfparser_test.cpp => cuReMFParser.cpp} (97%) rename cunit/{rplmatrix_test.cpp => cuReMatrix.cpp} (98%) create mode 100644 cunit/cuReQStringUtil.cpp rename cunit/{rplsource_test.cpp => cuReSource.cpp} (96%) rename cunit/{rplstring_test.cpp => cuReStringUtil.cpp} (92%) create mode 100644 cunit/cuReTraverser.cpp rename cunit/{rplvm_test.cpp => cuReVM.cpp} (96%) rename cunit/{rplwriter_test.cpp => cuReWriter.cpp} (82%) delete mode 100644 cunit/main.cpp delete mode 100644 cunit/rplqstring_test.cpp create mode 100644 os/ReTraverser.cpp create mode 100644 os/ReTraverser.hpp create mode 100644 os/reos.hpp rename static/{rplstaticlib.cpp => ReStaticLib.cpp} (79%) delete mode 100644 static/rplstaticlib.hpp diff --git a/appl/qfilesearch b/appl/refind similarity index 100% rename from appl/qfilesearch rename to appl/refind diff --git a/base/ReContainer.cpp b/base/ReContainer.cpp index 6b7e5bf..67a439a 100644 --- a/base/ReContainer.cpp +++ b/base/ReContainer.cpp @@ -1,6 +1,6 @@ /* * ReContainer.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -266,7 +266,8 @@ void ReContainer::nextItem(type_tag_t expected){ m_ixItem = 0; } if (m_ixItem >= m_typeList.length()) - throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, "no more items in the bag"); + throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, ReLogger::globalLogger(), + "no more items in the bag"); type_tag_t current = (type_tag_t) m_typeList.at(m_ixItem); // Unify all data types: if (current == TAG_DATA4G || current == TAG_DATA64K) diff --git a/base/ReQString.cpp b/base/ReQString.cpp deleted file mode 100644 index a57930b..0000000 --- a/base/ReQString.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * ReQString.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Missed operation for ReStrings. - */ -/** @file rplcore/rplqstring.hpp - * - * @brief Definitions for missed operation for ReStrings. - */ -#include "base/rebase.hpp" - -/** - * @brief Determines the length and vlaue of an integer. - * - * @param text the number as text - * @param start the first index to inspect - * @param radix the base of the number sytem: 8 (octal), 10 or 16 - * @param pValue OUT: the value of the integer. May be NULL - * - * @return <=0: no integer found - * otherwise: the length of the integer - */ -int ReQString::lengthOfUInt64(const ReString& text, int start, int radix, - quint64* pValue){ - int inputLength = text.size(); - int64_t value = 0; - int ix = start; - int cc; - if (radix == 10){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 10 + cc - '0'; - else - break; - ix++; - } - }else if (radix == 16){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 16 + cc - '0'; - else if (cc >= 'A' && cc <= 'F') - value = value * 16 + cc - 'A' + 10; - else if (cc >= 'a' && cc <= 'f') - value = value * 16 + cc - 'a' + 10; - else - break; - ix++; - } - }else if (radix == 8){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '7') - value = value * 8 + cc - '0'; - else - break; - ix++; - } - }else{ - throw ReException("ReQString::lengthOfInt(): wrong radix: %d", radix); - } - if (pValue != NULL) - *pValue = value; - return ix - start; -} -/** - * @brief Determines the length and value of an unsigned integer. - * - * @param text the number as text - * @param start the first index to inspect - * @param radix the base of the number sytem: 8 (octal), 10 or 16 - * @param pValue OUT: the value of the integer. May be NULL - * - * @return 0: no integer found - * otherwise: the length of the integer - */ -int ReQString::lengthOfUInt(const ReString& text, int start, int radix, - uint* pValue){ - quint64 value; - int rc = lengthOfUInt64(text, start, radix, &value); - if (pValue != NULL) - *pValue = (uint) value; - return rc; -} - -/** - * @brief Determines the length and value of a floting point number. - * - * @param text the number as text - * @param start the first index to inspect - * @param pValue OUT: the value of the integer. May be NULL - * - * @return <=0: no real number found - * otherwise: the length of the floating point number - */ -int ReQString::lengthOfReal(const ReString& text, int start, qreal* pValue){ - int inputLength = text.size(); - qreal value = 0.0; - int cc; - int ix = start; - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 10 + (cc - '0'); - else - break; - ix++; - } - // found: a digit has been found (in front of or behind the '.' - bool found = ix > start; - if (ix < inputLength && text[ix].unicode() == '.'){ - ix++; - } - if (ix < inputLength && text[ix].isDigit()){ - found = true; - qreal divisor = 1; - qreal precision = 0; - while (ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){ - divisor *= 10; - precision = precision * 10 + cc - '0'; - ix++; - } - value += precision / divisor; - }else if (!found){ - ix = start; - } - if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){ - int savePoint = ix; - ix++; - bool negative = false; - if ((cc = text[ix].unicode()) == '+') - ix++; - else if (cc == '-'){ - ix++; - negative = true; - } - if (ix >= inputLength || !text[ix].isDigit()) - ix = savePoint; - else{ - int exponent = 0; - while (ix < inputLength && text[ix].isDigit()){ - exponent = exponent * 10 + text[ix].unicode() - '0'; - ix++; - } - if (negative) - value /= qPow(10, exponent); - else - value *= qPow(10, exponent); - } - } - if (pValue) - *pValue = value; - return found ? ix - start : 0; -} - -/** - * @brief Converts a ReString into an utf-8 string - * - * The expression qstring.toUtf8().constData() is not allowed - * in a variable argument list like sprintf. This is a thread save workaround. - * - * @param source string to convert - * @param buffer OUT: target buffer - * @param bufferSize size of the target buffer - * @return buffer - */ -char*ReQString::utf8(const ReString& source, char buffer[], size_t bufferSize){ - QByteArray val = source.toUtf8(); - if (val.length() < (int) bufferSize) - bufferSize = val.length() + 1; - memcpy(buffer, val.constData(), bufferSize - 1); - buffer[bufferSize - 1] = '\0'; - return buffer; -} diff --git a/base/ReQStringUtil.cpp b/base/ReQStringUtil.cpp new file mode 100644 index 0000000..7dd4c06 --- /dev/null +++ b/base/ReQStringUtil.cpp @@ -0,0 +1,360 @@ +/* + * ReQStringUtil.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Missed operation for ReStrings. + */ +/** @file rplcore/rplqstring.hpp + * + * @brief Definitions for missed operation for ReStrings. + */ +#include "base/rebase.hpp" +#include +/** + * @brief Determines the length and vlaue of an integer. + * + * @param text the number as text + * @param start the first index to inspect + * @param radix the base of the number sytem: 8 (octal), 10 or 16 + * @param pValue OUT: the value of the integer. May be NULL + * + * @return <=0: no integer found + * otherwise: the length of the integer + */ +int ReQStringUtil::lengthOfUInt64(const ReString& text, int start, int radix, + quint64* pValue){ + int inputLength = text.size(); + int64_t value = 0; + int ix = start; + int cc; + if (radix == 10){ + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '9') + value = value * 10 + cc - '0'; + else + break; + ix++; + } + }else if (radix == 16){ + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '9') + value = value * 16 + cc - '0'; + else if (cc >= 'A' && cc <= 'F') + value = value * 16 + cc - 'A' + 10; + else if (cc >= 'a' && cc <= 'f') + value = value * 16 + cc - 'a' + 10; + else + break; + ix++; + } + }else if (radix == 8){ + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '7') + value = value * 8 + cc - '0'; + else + break; + ix++; + } + }else{ + throw ReException("ReQStringUtil::lengthOfInt(): wrong radix: %d", radix); + } + if (pValue != NULL) + *pValue = value; + return ix - start; +} +/** + * @brief Determines the length and value of an unsigned integer. + * + * @param text the number as text + * @param start the first index to inspect + * @param radix the base of the number sytem: 8 (octal), 10 or 16 + * @param pValue OUT: the value of the integer. May be NULL + * + * @return 0: no integer found + * otherwise: the length of the integer + */ +int ReQStringUtil::lengthOfUInt(const ReString& text, int start, int radix, + uint* pValue){ + quint64 value; + int rc = lengthOfUInt64(text, start, radix, &value); + if (pValue != NULL) + *pValue = (uint) value; + return rc; +} + +/** + * @brief Determines the length and value of a floting point number. + * + * @param text the number as text + * @param start the first index to inspect + * @param pValue OUT: the value of the integer. May be NULL + * + * @return <=0: no real number found + * otherwise: the length of the floating point number + */ +int ReQStringUtil::lengthOfReal(const ReString& text, int start, qreal* pValue){ + int inputLength = text.size(); + qreal value = 0.0; + int cc; + int ix = start; + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '9') + value = value * 10 + (cc - '0'); + else + break; + ix++; + } + // found: a digit has been found (in front of or behind the '.' + bool found = ix > start; + if (ix < inputLength && text[ix].unicode() == '.'){ + ix++; + } + if (ix < inputLength && text[ix].isDigit()){ + found = true; + qreal divisor = 1; + qreal precision = 0; + while (ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){ + divisor *= 10; + precision = precision * 10 + cc - '0'; + ix++; + } + value += precision / divisor; + }else if (!found){ + ix = start; + } + if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){ + int savePoint = ix; + ix++; + bool negative = false; + if ((cc = text[ix].unicode()) == '+') + ix++; + else if (cc == '-'){ + ix++; + negative = true; + } + if (ix >= inputLength || !text[ix].isDigit()) + ix = savePoint; + else{ + int exponent = 0; + while (ix < inputLength && text[ix].isDigit()){ + exponent = exponent * 10 + text[ix].unicode() - '0'; + ix++; + } + if (negative) + value /= qPow(10, exponent); + else + value *= qPow(10, exponent); + } + } + if (pValue) + *pValue = value; + return found ? ix - start : 0; +} + +/** + * @brief Converts a ReString into an utf-8 string + * + * The expression qstring.toUtf8().constData() is not allowed + * in a variable argument list like sprintf. This is a thread save workaround. + * + * @param source string to convert + * @param buffer OUT: target buffer + * @param bufferSize size of the target buffer + * @return buffer + */ +char*ReQStringUtil::utf8(const ReString& source, char buffer[], + size_t bufferSize){ + QByteArray val = source.toUtf8(); + if (val.length() < (int) bufferSize) + bufferSize = val.length() + 1; + memcpy(buffer, val.constData(), bufferSize - 1); + buffer[bufferSize - 1] = '\0'; + return buffer; +} + +class ReParserException : public ReException { +public: + ReParserException(const QString& message) : + ReException(), + m_message(message){ + } +public: + QString m_message; +}; +/** + * Constructor. + * + * @param expr an expression, e.g. "10*1024kByte+5MiByte" + * @param unitList description of the allowed units with its factor
+ * example: "kibyte:1024;kbyte:1000;mibyte:1048576;mbyte:1000000" + */ +ReUnitParser::ReUnitParser(const QString& expr, const char* unitList) : + m_result(0), m_expr(expr), m_message(), m_unitList(unitList){ + // Replace the '-' operator by '+' as operator and '-' as sign: + // This makes the syntax easier to parse: only one sum operator ('+'). + for (int ii = m_expr.length() - 1; ii > 0; ii--){ + if (m_expr[ii] == '-' && m_expr[ii -1] != '+' && m_expr[ii - 1] != '*'){ + m_expr.insert(ii, '+'); + } + } + parse(); +} +/** + * Returns whether the given expression is valid. + * + * @return true: the expression is valid, a result was calculated + */ +bool ReUnitParser::isValid() const{ + return m_message.isEmpty(); +} +/** + * Returns an empty string or the error message. + * + * @return "": no error occurred
+ * otherwise: the error message + */ +const QString& ReUnitParser::errorMessage() const{ + return m_message; +} +/** + * Returns the result of the expression as a 64 bit integer. + * + * @param defaultValue the result if the expression was not valid + * @return defaultValue: the result was not valid
+ * the result as a 64 bit integer + */ +int64_t ReUnitParser::asInt64(int64_t defaultValue){ + return m_message.isEmpty() ? m_result : defaultValue; +} +/** + * Returns the result of the expression as an integer. + * + * @param defaultValue the result if the expression was not valid + * @return defaultValue: the result was not valid
+ * the result as an integer + */ +int ReUnitParser::asInt(int defaultValue){ + return m_message.isEmpty() ? (int) m_result : defaultValue; +} +/** + * Returns the result of the expression as floating point number. + * + * @param defaultValue the result if the expression was not valid + * @return defaultValue: the result was not valid
+ * the result as a floating point + */ +real_t ReUnitParser::asReal(real_t defaultValue){ + return m_message.isEmpty() ? (real_t) m_result : defaultValue; +} + +/** + * Calculates the value of a number or a (number, unit) pair. + * + * @param value a non negative number or a number followed by a unit
+ * only units defined in m_unitList are allowed
+ * examples: "4kByte" returns 4000, "4kibyte" returns 4096 + * @return the value of the number multiplied by the factor given by the unit + * @throws ReParserException + */ +uint64_t ReUnitParser::valueOf(const QString& value) const{ + uint64_t rc = 0; + int ix = ReQStringUtil::lengthOfUInt64(value, 0, 10, &rc); + if (ix == 0) + throw ReParserException(QObject::tr("number expected: ") + value); + QString unit = value.mid(ix); + if (! unit.isEmpty()){ + QStringList units = QString(m_unitList).split(";"); + QStringList::const_iterator it; + bool found = false; + for (it = units.begin(); it != units.end(); ++it){ + QStringList pair = it->split(":"); + if (pair.count() == 0) + throw ReParserException(QObject::tr("missing ':' in unit definition, e.g. 'k:1000': ") + *it); + if (pair.count() > 2) + throw ReParserException(QObject::tr("too many ':' in unit definition: ") + *it); + bool ok = false; + QString unit2 = *pair.begin(); + QString factor = *++pair.begin(); + uint64_t nFactor = factor.toLongLong(&ok); + if (! ok) + throw ReParserException(QObject::tr("not a number: ") + factor); + if (unit2.startsWith(unit)){ + rc *= nFactor; + found = true; + break; + } + } + if (! found) + throw ReParserException(QObject::tr("unknown unit, allowed: ") + QString(m_unitList)); + } + return rc; +} +/** + * Evaluate the expression. + */ +void ReUnitParser::parse(){ + QStringList addends = m_expr.split("+"); + QStringList::const_iterator it; + try{ + m_result = 0; + for (it = addends.begin(); it != addends.end(); ++it){ + QStringList factors = it->split("*"); + QStringList::const_iterator it2; + int64_t product = 1; + for (it2 = factors.begin(); it2 != factors.end(); ++it2){ + QStringList powerOperands = it2->split("^"); + if (powerOperands.count() > 2) + throw ReParserException(QObject::tr("more than 2 power operators, e.g. '2^3^4'")); + QStringList::const_iterator it3 = powerOperands.begin(); + QString op = *it3; + bool isNeg = op.startsWith("-"); + if (isNeg) + op = op.mid(1); + uint64_t value = valueOf(op); + if (powerOperands.count() > 1){ + uint64_t fac = value; + uint64_t exponent = valueOf(*++it3); + if (qLn(value) * qLn(exponent) >= qLn(qPow(2.0, 64))) + throw ReParserException(QObject::tr("number overflow while power operation")); + for (int ii = 1; ii < (int) exponent; ii++) + value = value * fac; + } + product *= value; + if (isNeg) + product = -product; + } + m_result += product; + } + + } catch (ReParserException& e){ + m_message = e.m_message; + } +} + +/** + * Constructor. + * + * @param expr an expression, e.g. "10*1024kByte+5MiByte" + */ +ReSizeParser::ReSizeParser(const QString& expr) : + ReUnitParser(expr, "byte:1;kbyte:1000;kibyte:1024;" + "mbyte:1000000;mibyte:1048576;" + "gbyte:1000000000;gibyte:1073741824;" + "tbyte:1000000000000;tibyte:1099511627776"){ +} +/** + * Constructor. + * + * @param expr an expression, e.g. "3*3days-5min+3weeks" + */ +ReDateTimeParser::ReDateTimeParser(const QString& expr) : + ReUnitParser(expr, "minutes:60;hours:3600;days:86400;weeks:604800"){ +} diff --git a/base/ReQtring.hpp b/base/ReQStringUtil.hpp similarity index 61% rename from base/ReQtring.hpp rename to base/ReQStringUtil.hpp index 77e1e94..7af38e9 100644 --- a/base/ReQtring.hpp +++ b/base/ReQStringUtil.hpp @@ -1,6 +1,6 @@ /* * ReQtring.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -12,10 +12,10 @@ #ifndef RPLQSTRING_HPP #define RPLQSTRING_HPP -class ReQString { +class ReQStringUtil { public: static int lengthOfUInt64(const ReString& text, int start = 0, - int radix = 10, quint64* value = NULL); + int radix = 10, uint64_t* value = NULL); static int lengthOfUInt(const ReString& text, int start, int radix, uint* pValue); static int lengthOfReal(const ReString& text, int start = 0, qreal* value = @@ -35,4 +35,33 @@ public: static char* utf8(const ReString& source, char buffer[], size_t bufferSize); }; +class ReUnitParser { +public: + ReUnitParser(const QString& expr, const char* unitList); +public: + bool isValid() const; + const QString& errorMessage() const; + int64_t asInt64(int64_t defaultValue = -1ll); + int asInt(int defaultValue = -1); + real_t asReal(real_t defaultValue = -1.0); +private: + void parse(); + uint64_t valueOf(const QString& value) const; +private: + int64_t m_result; + QString m_expr; + QString m_message; + const char* m_unitList; +}; + +class ReSizeParser : public ReUnitParser { +public: + ReSizeParser(const QString& expr); +}; + +class ReDateTimeParser : public ReUnitParser { +public: + ReDateTimeParser(const QString& expr); +}; + #endif // RPLQSTRING_HPP diff --git a/base/ReTerminator.hpp b/base/ReTerminator.hpp index d72d627..d8a193d 100644 --- a/base/ReTerminator.hpp +++ b/base/ReTerminator.hpp @@ -1,6 +1,6 @@ /* * ReTerminator.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. diff --git a/base/ReTest.cpp b/base/ReTest.cpp index 22253b4..a8f9537 100644 --- a/base/ReTest.cpp +++ b/base/ReTest.cpp @@ -1,6 +1,6 @@ /* * ReTest.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -42,19 +42,21 @@ ReTest::ReTest(const char* name) : m_logger.buildStandardAppender(getTempDir("rpltest")); log(QByteArray("Start of ") + m_name); m_memoryLogger.addAppender(&m_memoryAppender); - try{ - run(); - } catch (ReException e){ - error("unexpected RplException: %s", e.getMessage().constData()); - } catch (...){ - error("unknown Exception"); - } +} +void ReTest::doIt(){ + try{ + run(); + } catch (ReException e){ + error("unexpected RplException: %s", e.getMessage().constData()); + } catch (...){ + error("unknown Exception"); + } - if (m_errors > 0){ - error("Unit %s has %d error(s)", m_name.data(), m_errors); - // error() increments, we decrement: - m_errors--; - } + if (m_errors > 0){ + error("Unit %s has %d error(s)", m_name.data(), m_errors); + // error() increments, we decrement: + m_errors--; + } } /** diff --git a/base/ReTest.hpp b/base/ReTest.hpp index 9b27d01..0e85581 100644 --- a/base/ReTest.hpp +++ b/base/ReTest.hpp @@ -1,6 +1,6 @@ /* * ReTest.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -21,6 +21,8 @@ private: ReTest(const ReTest& source); // Prohibits assignment operator: no implementation! ReTest& operator =(const ReTest& source); +protected: + void doIt(); public: bool assertEquals(int expected, int current, const char* file, int lineNo); bool assertEquals(int64_t expected, int64_t current, const char* file, diff --git a/base/rebase.hpp b/base/rebase.hpp index b7cb676..c8f0d85 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -8,8 +8,8 @@ * You also can use this license: http://www.wtfpl.net * The latest sources: https://github.com/republib */ -#ifndef RECORE_HPP -#define RECORE_HPP +#ifndef REBASE_HPP +#define REBASE_HPP #include #include @@ -20,9 +20,6 @@ #include #include -#include -#include -#include #include #include #include @@ -32,7 +29,7 @@ #include #include #include - +#include typedef unsigned char uint8_t; //typedef qint64 int64_t; typedef quint64 uint64_t; @@ -50,10 +47,10 @@ typedef QString ReString; #include "base/ReException.hpp" #include "base/ReContainer.hpp" #include "base/ReStringUtil.hpp" -#include "base/ReQtring.hpp" +#include "ReQStringUtil.hpp" #include "base/ReConfigurator.hpp" #include "base/ReConfig.hpp" #include "base/ReTerminator.hpp" #include "base/ReTest.hpp" -#endif // RECORE_HPP +#endif // REBASE_HPP diff --git a/base/testrplexample.cpp b/base/testrplexample.cpp index a220646..f4c53dc 100644 --- a/base/testrplexample.cpp +++ b/base/testrplexample.cpp @@ -1,6 +1,6 @@ /* * testrplexample.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -10,7 +10,7 @@ */ include "project.hpp" -#include "base/base.hpp" +#include "base/rebase.hpp" // Code to test: int add(int a, int b){ return a+b; diff --git a/cunit/allTests.cpp b/cunit/allTests.cpp new file mode 100644 index 0000000..dea96b8 --- /dev/null +++ b/cunit/allTests.cpp @@ -0,0 +1,81 @@ +/* + * allTests.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use the license from http://www.wtfpl.net/. + * The latest sources: https://github.com/republib + */ +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +//#include "os/reos.hpp" + +static bool s_allTest = true; + +static void testBase(){ + void testReByteStorage(); + void testReCharPtrMap(); + void testReConfig(); + void testReContainer(); + void testReException(); + void testReQStringUtil(); + void testReStringUtil(); + void testReWriter(); + + testReQStringUtil(); + if (s_allTest){ + testReByteStorage(); + testReCharPtrMap(); + testReConfig(); + testReContainer(); + testReException(); + testReQStringUtil(); + testReStringUtil(); + testReWriter(); + } +} +static void testMath(){ + +} +static void testExpr(){ + extern void testReMFParser(); + extern void testRplBenchmark(); + extern void testReVM(); + extern void testReSource(); + extern void testReLexer(); + extern void testReMFParser(); + extern void testReASTree(); + extern void testReVM(); + + //testRplBenchmark(); + if (s_allTest){ + testReVM(); + testReSource(); + testReLexer(); + testReMFParser(); + testReASTree(); + testReVM(); + } +} +static void testNet(){ + +} +static void testOs(){ + +} +void allTests(){ + testBase(); + if (s_allTest){ + testBase(); + testMath(); + testExpr(); + testNet(); + testOs(); + } +} + + + diff --git a/cunit/rplastree_test.cpp b/cunit/cuReASTree.cpp similarity index 97% rename from cunit/rplastree_test.cpp rename to cunit/cuReASTree.cpp index 0a98a23..fde8699 100644 --- a/cunit/rplastree_test.cpp +++ b/cunit/cuReASTree.cpp @@ -1,6 +1,6 @@ /* * rplastree_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -16,7 +16,6 @@ #include "base/rebase.hpp" #include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" class TestReASTree : public ReTest{ private: @@ -87,7 +86,7 @@ public: ReASNamedValue::A_GLOBAL); checkEqu("gugo", value.name()); } - virtual void doIt() { + virtual void run() { testReASNamedValue(); testReASConstant(); testReASException(); @@ -96,7 +95,6 @@ public: }; void testReASTree() { TestReASTree test; - test.run(); } diff --git a/cunit/rplbench.cpp b/cunit/cuReBench.cpp similarity index 96% rename from cunit/rplbench.cpp rename to cunit/cuReBench.cpp index 31f0e8a..5a87df4 100644 --- a/cunit/rplbench.cpp +++ b/cunit/cuReBench.cpp @@ -1,6 +1,6 @@ /* * rplbench.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -16,7 +16,6 @@ #include "base/rebase.hpp" #include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" class TestRplBenchmark : public ReTest{ private: @@ -43,7 +42,7 @@ public: time_t end = time(NULL); printf("compilation: %d sec\n", int(end - start)); } - virtual void doIt() { + virtual void run() { try{ ReFileSourceUnit* unit = dynamic_cast (m_reader.currentSourceUnit()); diff --git a/cunit/rplbytestorage_test.cpp b/cunit/cuReByteStorage.cpp similarity index 86% rename from cunit/rplbytestorage_test.cpp rename to cunit/cuReByteStorage.cpp index 0f40bc6..fb8cf6d 100644 --- a/cunit/rplbytestorage_test.cpp +++ b/cunit/cuReByteStorage.cpp @@ -1,6 +1,6 @@ /* * rplbytestorage_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -12,14 +12,13 @@ * @brief Unit test of the byte and C string storage. */ -#include "../base/rebase.hpp" -#include "../base/ReTest.hpp" +#include "base/rebase.hpp" -class TestRplByteStorage : public ReTest{ +class TestReByteStorage : public ReTest{ public: - TestRplByteStorage() : - ReTest("RplByteStorage") - {} + TestReByteStorage() : + ReTest("ReByteStorage") + { doIt(); } private: void testChars(){ ReByteStorage store(100); @@ -66,15 +65,14 @@ private: } public: - virtual void doIt() { + virtual void run() { testBufferChange(); testChars(); testBytes(); } }; -void testRplByteStorage() { - TestRplByteStorage test; - test.run(); +void testReByteStorage() { + TestReByteStorage test; } diff --git a/cunit/rplcharptrmap_test.cpp b/cunit/cuReCharPtrMap.cpp similarity index 89% rename from cunit/rplcharptrmap_test.cpp rename to cunit/cuReCharPtrMap.cpp index 0643b9e..2d5df72 100644 --- a/cunit/rplcharptrmap_test.cpp +++ b/cunit/cuReCharPtrMap.cpp @@ -1,6 +1,6 @@ /* * rplcharptrmap_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -10,13 +10,13 @@ */ #include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" class TestReCharPtrMap : public ReTest{ public: TestReCharPtrMap() : ReTest("ReCharPtrMap") { + doIt(); } protected: void testBasic(){ @@ -26,12 +26,11 @@ protected: checkF(map.contains("y")); checkEqu("x1", map["x"]); } - - virtual void doIt(void) { +public: + virtual void run(void) { testBasic(); } }; void testReCharPtrMap() { TestReCharPtrMap test; - test.run(); } diff --git a/cunit/cuReConfig.cpp b/cunit/cuReConfig.cpp index 535347d..01daeb5 100644 --- a/cunit/cuReConfig.cpp +++ b/cunit/cuReConfig.cpp @@ -17,6 +17,7 @@ class TestReConfig: public ReTest { public: TestReConfig() : ReTest("ReConfig") { + doIt(); } public: diff --git a/cunit/cuReContainer.cpp b/cunit/cuReContainer.cpp index e418b4e..ff368c6 100644 --- a/cunit/cuReContainer.cpp +++ b/cunit/cuReContainer.cpp @@ -1,6 +1,6 @@ /* * cuReContainer.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -12,9 +12,9 @@ /** * @brief Unit test for ReContainer */ -class TestRplContainer : public ReTest { +class TestReContainer : public ReTest { public: - TestRplContainer() : ReTest("RplContainer") {} + TestReContainer() : ReTest("RplContainer") { doIt(); } public: void testBasic() { @@ -50,8 +50,8 @@ public: } }; -void testRplContainer() { - TestRplContainer test; +void testReContainer() { + TestReContainer test; } diff --git a/cunit/cuReEnigma.cpp b/cunit/cuReEnigma.cpp index 44912aa..bc07e17 100644 --- a/cunit/cuReEnigma.cpp +++ b/cunit/cuReEnigma.cpp @@ -1,6 +1,6 @@ /* * cuReEnigma.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -9,12 +9,13 @@ * The latest sources: https://github.com/republib */ #include "base/rebase.hpp" +#include "math/remath.hpp" /** * @brief Unit test for ReEnigma. */ class TestReEnigma : public ReTest { public: - TestReEnigma() : ReTest("ReEnigma") {} + TestReEnigma() : ReTest("ReEnigma") { doIt(); } public: void testOneCharset(const char* value, const char* charSet, @@ -103,7 +104,7 @@ public: "850592651836811261879625929"); } - virtual void doIt() { + virtual void run() { testBytes(); testCharSet(); } @@ -111,5 +112,4 @@ public: void testReEnigma() { TestReEnigma test; - test.run(); } diff --git a/cunit/rplexception_test.cpp b/cunit/cuReException.cpp similarity index 84% rename from cunit/rplexception_test.cpp rename to cunit/cuReException.cpp index f219850..1230b73 100644 --- a/cunit/rplexception_test.cpp +++ b/cunit/cuReException.cpp @@ -1,6 +1,6 @@ /* * rplexception_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -9,14 +9,14 @@ * The latest sources: https://github.com/republib */ #include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" + /** @file * @brief Unit test of the basic exceptions. */ -class TestRplException : public ReTest{ +class TestReException : public ReTest{ public: - TestRplException() : ReTest("RplException") {} + TestReException() : ReTest("RplException") { doIt(); } public: void testBasic() { @@ -41,13 +41,12 @@ public: } log("ok"); } - virtual void doIt() { + virtual void run() { testBasic(); } }; -void testRplException() { - TestRplException test; - test.run(); +void testReException() { + TestReException test; } diff --git a/cunit/rpllexer_test.cpp b/cunit/cuReLexer.cpp similarity index 99% rename from cunit/rpllexer_test.cpp rename to cunit/cuReLexer.cpp index 72f133e..3cdb2ed 100644 --- a/cunit/rpllexer_test.cpp +++ b/cunit/cuReLexer.cpp @@ -1,6 +1,6 @@ /* * rpllexer_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -15,7 +15,6 @@ #include "base/rebase.hpp" #include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" class TestRplLexer : public ReTest, public ReToken{ public: @@ -264,7 +263,7 @@ public: checkEqu(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV)); } - virtual void doIt(void) { + virtual void run(void) { testPrio(); testBasic(); testIds(); @@ -277,7 +276,7 @@ public: testRplToken(); } }; -void testRplLexer() { +void testReLexer() { TestRplLexer test; test.run(); } diff --git a/cunit/rplmfparser_test.cpp b/cunit/cuReMFParser.cpp similarity index 97% rename from cunit/rplmfparser_test.cpp rename to cunit/cuReMFParser.cpp index a234542..04df740 100644 --- a/cunit/rplmfparser_test.cpp +++ b/cunit/cuReMFParser.cpp @@ -1,6 +1,6 @@ /* * rplmfparser_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -14,9 +14,8 @@ #include "base/rebase.hpp" #include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" -class TestRplMFParser : public ReTest{ +class TestReMFParser : public ReTest{ private: ReSource m_source; ReASTree m_tree; @@ -24,7 +23,7 @@ private: ReFileReader m_fileReader; QByteArray m_currentSource; public: - TestRplMFParser() : + TestReMFParser() : ReTest("ReMFParser"), m_source(), m_tree(), @@ -32,6 +31,7 @@ public: m_fileReader(m_source) { m_source.addReader(&m_reader); + doIt(); } protected: void setSource(const char* content){ @@ -204,7 +204,7 @@ public: checkAST("main1.txt", __LINE__); } - virtual void doIt(void) { + virtual void run(void) { mainTest(); varDefTest(); repeatTest(); @@ -221,9 +221,8 @@ public: fileClassTest(); } }; -void testRplMFParser() { - TestRplMFParser test; - test.run(); +void testReMFParser() { + TestReMFParser test; } diff --git a/cunit/rplmatrix_test.cpp b/cunit/cuReMatrix.cpp similarity index 98% rename from cunit/rplmatrix_test.cpp rename to cunit/cuReMatrix.cpp index 2b30e7a..55b568e 100644 --- a/cunit/rplmatrix_test.cpp +++ b/cunit/cuReMatrix.cpp @@ -1,6 +1,6 @@ /* * rplmatrix_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -14,12 +14,11 @@ */ #include "base/rebase.hpp" -#include "rplmath/rplmath.hpp" -#include "rplcore/rpltest.hpp" +#include "math/remath.hpp" class TestRplMatrix : public ReTest{ public: - TestRplMatrix() : ReTest("RplMatrix") {} + TestRplMatrix() : ReTest("RplMatrix") { doIt(); } public: void fillMatrix(RplMatrix& mx, MatVal offset = 0){ @@ -356,7 +355,7 @@ public: int maxLineLength = 1024*1024); */ } - virtual void doIt(void) { + virtual void run(void) { testBasic(); testAddOperators(); testCompareOperators(); @@ -372,5 +371,4 @@ public: }; void testRplMatrix() { TestRplMatrix test; - test.run(); } diff --git a/cunit/cuReQStringUtil.cpp b/cunit/cuReQStringUtil.cpp new file mode 100644 index 0000000..c04145d --- /dev/null +++ b/cunit/cuReQStringUtil.cpp @@ -0,0 +1,151 @@ +/* + * rplqstring_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ +/** @file + * @brief Unit test of the ReString tools. + */ + +#include "base/rebase.hpp" + +class TestReQStringUtil : public ReTest { +public: + TestReQStringUtil() : + ReTest("ReQStringUtil") + { doIt(); } + +public: + void testLengthOfUInt64(){ + quint64 value = -3; + checkEqu(1, ReQStringUtil::lengthOfUInt64(ReString("0"), 0, 10, &value)); + checkEqu(int64_t(0), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("x432", 1, 10, &value)); + checkEqu(int64_t(432LL), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("x432 x", 1, 10, &value)); + checkEqu(int64_t(432LL), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("x432fabc x", 1, 10, &value)); + checkEqu(int64_t(432LL), value); + checkEqu(16, ReQStringUtil::lengthOfUInt64("a1234567890123567", 1, 10, &value)); + checkEqu(int64_t(1234567890123567LL), value); + checkEqu(10, ReQStringUtil::lengthOfUInt64("x1234abcdef", 1, 16, &value)); + checkEqu(int64_t(0x1234abcdefLL), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("432", 0, 8, &value)); + checkEqu(int64_t(0432LL), value); + checkEqu(6, ReQStringUtil::lengthOfUInt64(" 765432 ", 1, 8, &value)); + checkEqu(int64_t(0765432LL), value); + + checkEqu(0, ReQStringUtil::lengthOfUInt64("1 ", 1, 8, &value)); + checkEqu(0, ReQStringUtil::lengthOfUInt64("", 1, 8, &value)); + } + void testLengthOfUInt(){ + uint value = 3; + checkEqu(1, ReQStringUtil::lengthOfUInt(ReString("0"), 0, 10, &value)); + checkEqu(0, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("x432", 1, 10, &value)); + checkEqu(432, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("x432 x", 1, 10, &value)); + checkEqu(432, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("x432fabc x", 1, 10, &value)); + checkEqu(432, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("432", 0, 8, &value)); + checkEqu(0432, value); + checkEqu(6, ReQStringUtil::lengthOfUInt(" 765432 ", 1, 8, &value)); + checkEqu(0765432, value); + + checkEqu(0, ReQStringUtil::lengthOfUInt("1 ", 1, 8, &value)); + checkEqu(0, ReQStringUtil::lengthOfUInt("", 1, 8, &value)); + } + void testLengthOfReal(){ + qreal value; + checkEqu(4, ReQStringUtil::lengthOfReal(ReString("0.25"), 0, &value)); + checkEqu(0.25, value); + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("X.25"), 1, &value)); + checkEqu(0.25, value); + checkEqu(1, ReQStringUtil::lengthOfReal(ReString(" 0"), 1, &value)); + checkEqu(0.0, value); + checkEqu(17, ReQStringUtil::lengthOfReal(ReString("X12345678901234567"), 1, &value)); + checkEqu(12345678901234567.0, value); + checkEqu(2, ReQStringUtil::lengthOfReal(ReString(".5"), 0, &value)); + checkEqu(0.5, value); + checkEqu(5, ReQStringUtil::lengthOfReal(ReString("2.5e2x"), 0, &value)); + checkEqu(250.0, value); + checkEqu(6, ReQStringUtil::lengthOfReal(ReString("2.5e+2"), 0, &value)); + checkEqu(250.0, value); + checkEqu(7, ReQStringUtil::lengthOfReal(ReString("2.5E-33"), 0, &value)); + checkEqu(2.5e-33, value); + + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("2.5E"), 0, &value)); + checkEqu(2.5, value); + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("2.5E+"), 0, &value)); + checkEqu(2.5, value); + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("2.5E-a"), 0, &value)); + checkEqu(2.5, value); + } + + void testValueOfHexDigit(){ + checkEqu(0, ReQStringUtil::valueOfHexDigit('0')); + checkEqu(9, ReQStringUtil::valueOfHexDigit('9')); + checkEqu(10, ReQStringUtil::valueOfHexDigit('a')); + checkEqu(15, ReQStringUtil::valueOfHexDigit('f')); + checkEqu(10, ReQStringUtil::valueOfHexDigit('A')); + checkEqu(15, ReQStringUtil::valueOfHexDigit('F')); + + checkEqu(-1, ReQStringUtil::valueOfHexDigit('0' - 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('9' + 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('A' - 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('F' + 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('a' - 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('f' + 1)); + } + void testUtf8(){ + ReString name = "Heinz Müller"; + char buffer[32]; + checkEqu("Heinz Müller", ReQStringUtil::utf8(name, buffer, sizeof buffer)); + memset(buffer, 'x', sizeof buffer); + checkEqu("Heinz", ReQStringUtil::utf8(name, buffer, (size_t) (5+1))); + checkEqu(buffer[6], 'x'); + } + + void testUnitParser(){ + ReUnitParser parser("-1-2*3*4+2^3*4", NULL); + checkT(parser.isValid()); + checkEqu(7, parser.asInt()); + checkEqu(7LL, parser.asInt64()); + checkEqu(7.0, parser.asReal()); + } + void testSizeParser(){ + ReSizeParser parser("2^3byte+2*1k+1m+1g+1t"); + checkT(parser.isValid()); + checkEqu(1001001002008LL, parser.asInt64()); + + ReSizeParser parser2("1ki+1mi+1gi+1ti"); + checkT(parser2.isValid()); + checkEqu(1100586419200ll, parser2.asInt64()); + } + void testDateTimeParser(){ + ReDateTimeParser parser("1+1min+1h+1day+1week"); + checkT(parser.isValid()); + checkEqu(694861, parser.asInt()); + } + + virtual void run(void) { + testUnitParser(); + testSizeParser(); + testDateTimeParser(); + testUtf8(); + testLengthOfUInt64(); + testLengthOfUInt(); + testLengthOfReal(); + testValueOfHexDigit(); + } +}; +void testReQStringUtil() { + TestReQStringUtil test; +} + diff --git a/cunit/rplsource_test.cpp b/cunit/cuReSource.cpp similarity index 96% rename from cunit/rplsource_test.cpp rename to cunit/cuReSource.cpp index 83fd0ec..05b1b32 100644 --- a/cunit/rplsource_test.cpp +++ b/cunit/cuReSource.cpp @@ -1,6 +1,6 @@ /* * rplsource_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -15,11 +15,10 @@ #include "base/rebase.hpp" #include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" class TestReSource : public ReTest{ public: - TestReSource() : ReTest("TestReSource") {} + TestReSource() : ReTest("TestReSource") { doIt(); } private: QByteArray m_content1_1; @@ -97,7 +96,7 @@ protected: } public: - virtual void doIt(void) { + void run(void) { init(); testReStringSourceUnit(); testReStringReader(); @@ -105,7 +104,6 @@ public: }; void testReSource() { TestReSource test; - test.run(); } diff --git a/cunit/rplstring_test.cpp b/cunit/cuReStringUtil.cpp similarity index 92% rename from cunit/rplstring_test.cpp rename to cunit/cuReStringUtil.cpp index c2e7dc8..e107a24 100644 --- a/cunit/rplstring_test.cpp +++ b/cunit/cuReStringUtil.cpp @@ -1,6 +1,6 @@ /* * rplstring_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -13,13 +13,12 @@ * @brief Unit test of the QByteArray tools. */ #include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" /** * @brief Unit test for ReStringUtil. */ -class TestReString : public ReTest { +class TestReStringUtil : public ReTest { public: - TestReString() : ReTest("ReStringUtil") {} + TestReStringUtil() : ReTest("ReStringUtil") { doIt(); } public: void testCountChar(){ @@ -127,21 +126,21 @@ public: void testLengthOfUInt64(){ quint64 value = -3; checkEqu(1, ReStringUtil::lengthOfUInt64("0", 10, &value)); - checkEqu(0LL, value); + checkEqu((int64_t) 0LL, value); checkEqu(3, ReStringUtil::lengthOfUInt64("432", 10, &value)); - checkEqu(432LL, value); + checkEqu((int64_t) 432LL, value); checkEqu(3, ReStringUtil::lengthOfUInt64("432 x", 10, &value)); - checkEqu(432LL, value); + checkEqu((int64_t) 432LL, value); checkEqu(3, ReStringUtil::lengthOfUInt64("432fabc x", 10, &value)); - checkEqu(432LL, value); + checkEqu((int64_t) 432LL, value); checkEqu(16, ReStringUtil::lengthOfUInt64("1234567890123567", 10, &value)); - checkEqu(1234567890123567LL, value); + checkEqu((int64_t) 1234567890123567LL, value); checkEqu(10, ReStringUtil::lengthOfUInt64("1234abcdef", 16, &value)); - checkEqu(0x1234abcdefLL, value); + checkEqu((int64_t) 0x1234abcdefLL, value); checkEqu(3, ReStringUtil::lengthOfUInt64("432", 8, &value)); - checkEqu(0432LL, value); + checkEqu((int64_t) 0432LL, value); checkEqu(6, ReStringUtil::lengthOfUInt64("765432 ", 8, &value)); - checkEqu(0765432LL, value); + checkEqu((int64_t) 0765432LL, value); checkEqu(0, ReStringUtil::lengthOfUInt64(" ", 8, &value)); checkEqu(0, ReStringUtil::lengthOfUInt64("", 8, &value)); @@ -175,7 +174,7 @@ public: checkEqu(2.5, value); } - virtual void doIt() { + virtual void run() { testLengthOfReal(); testLengthOfUInt64(); testCountChar(); @@ -190,9 +189,8 @@ public: } }; -void testReString() { - TestReString test; - test.run(); +void testReStringUtil() { + TestReStringUtil test; } diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp new file mode 100644 index 0000000..90cc05c --- /dev/null +++ b/cunit/cuReTraverser.cpp @@ -0,0 +1,155 @@ +/* + * cuReTraverser.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" +#include "os/reos.hpp" + +class TestReTraverser: public ReTestUnit { +public: + TestReTraverser() : + ReTestUnit("ReTraverser", __FILE__), + m_base(), + m_buffer(), + m_logger(ReLogger::globalLogger()) { + m_base = testDir(); + 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; + ReByteBuffer m_buffer; + ReLogger* m_logger; +private: + const char* makeDir(const char* relPath) { + m_buffer = m_base; + m_buffer.append(relPath); + m_buffer.replaceAll("/", 1, OS_SEPARATOR, -1); + _mkdir(m_buffer.str(), ALLPERMS); + struct stat info; + if (stat(m_buffer.str(), &info) != 0) { + logF(true, "cannot create dir %1$s", m_buffer.str()); + } + return m_buffer.str(); + } + void makeFile(const char* relPath) { + ReByteBuffer path(m_base); + path.append("/").append(relPath); + path.replaceAll("/", 1, OS_SEPARATOR, -1); + createFile(path.str(), relPath); + struct stat info; + if (stat(path.str(), &info) != 0) { + logF(true, "cannot create file %1$s", path.str()); + } + } + void initTree() { + makeFile("1.txt"); + makeDir("dir1"); + makeDir("dir2"); + makeDir("dir1/dir1_1"); + makeDir("dir1/dir1_2"); + makeDir("dir1/dir1_2/dir1_2_1"); + makeDir("dir1/cache"); + makeFile("dir1/dir1_2/dir1_2_1/x1.txt"); + makeFile("dir1/dir1_2/dir1_2_1/x2.txt"); + makeFile("dir2/2.x"); + makeFile("dir1/cache/cache.txt"); + } + void run() { + testFilter(); + initTree(); + + testBasic(); + testList(); + } + void testFilter() { + ReDirEntryFilter filter; + + } + void testList() { + const char* argv[] = { "list", m_base.str(), NULL }; + ReDirList(m_logger).run(2, argv); + } + void testCopyFile() { +#if defined __linux__ + ReByteBuffer src(m_base); + src.append("dir1/dir1_2/dir1_2_1/x1.txt"); + ReByteBuffer trg(testDir()); + trg.append("copy_x1.txt"); + ReByteBuffer buffer; + buffer.ensureSize(5); + ReDirSync::copyFile(src.str(), NULL, trg.str(), buffer, + ReLogger::globalLogger()); + checkFileEqu(src.str(), trg.str()); +#else + log(false, "testCopyFile not implemented"); +#endif + } + + void checkRelDate(time_t absTime, int relTime) { + int diff = int(time(NULL) - relTime - absTime); + if (diff < 0) + diff = -diff; + checkT(diff < 2); + } + + void checkOneFile(const char* node, const char* parent, + const ReHashList& hash) { + ReByteBuffer path, expected; + checkT(hash.get(ReByteBuffer(node), path)); + expected.set(parent, -1); + if (!expected.endsWith(OS_SEPARATOR)) + expected.append(OS_SEPARATOR); + if (!path.endsWith(expected.str(), -1)) + checkT(false); + } + void testBasic() { + ReTraverser traverser(m_base.str()); + RePatternList patterns; + // exclude */cache/* + ReByteBuffer buffer(";*;-cache"); + patterns.set(buffer.str()); + traverser.setDirPattern(&patterns); + int level = 0; + ReDirStatus_t* entry; + ReHashList hashPath; + ReSeqArray listChanged; + int state = 0; + while ((entry = traverser.rawNextFile(level)) != NULL) { + const char* node = entry->node(); + hashPath.put(ReByteBuffer(node, -1), entry->m_path); + if (traverser.hasChangedPath(state)) + listChanged.add(-1, node); + logF(false, "%d: %-12s %2d %s", level, node, int(entry->fileSize()), + entry->m_path.str()); + } + checkOneFile("x1.txt", "dir1_2_1", hashPath); + checkOneFile("x2.txt", "dir1_2_1", hashPath); + bool changed1 = listChanged.find("x1.txt") != (ReSeqArray::Index) -1; + bool changed2 = listChanged.find("x2.txt") != (ReSeqArray::Index) -1; + checkT(changed1 != changed2); + checkOneFile("dir1_2_1", "dir1_2", hashPath); + checkT(listChanged.find("dir1_2_1") >= 0); + checkOneFile("dir1_1", "dir1", hashPath); + checkOneFile("dir1_2", "dir1", hashPath); + changed1 = listChanged.find("dir1_1") != (ReSeqArray::Index) -1; + changed2 = listChanged.find("dir1_2") != (ReSeqArray::Index) -1; + checkT(changed1 != changed2); + checkF(hashPath.get("cache.txt", buffer)); + } +}; +extern void testReTraverser(void); + +void testReTraverser(void) { + TestReTraverser unit; +} diff --git a/cunit/rplvm_test.cpp b/cunit/cuReVM.cpp similarity index 96% rename from cunit/rplvm_test.cpp rename to cunit/cuReVM.cpp index 39df487..9befa8c 100644 --- a/cunit/rplvm_test.cpp +++ b/cunit/cuReVM.cpp @@ -1,6 +1,6 @@ /* * rplvm_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -11,7 +11,6 @@ #include "base/rebase.hpp" #include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" class TestReVM : public ReTest{ private: @@ -27,6 +26,7 @@ public: m_reader(m_source) { m_source.addReader(&m_reader); + doIt(); } protected: void setSource(const char* content){ @@ -64,12 +64,11 @@ public: setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf"); checkAST("baseTest.txt", __LINE__); } - virtual void doIt(void) { + virtual void run(void) { baseTest(); } }; void testReVM() { TestReVM test; - test.run(); } diff --git a/cunit/rplwriter_test.cpp b/cunit/cuReWriter.cpp similarity index 82% rename from cunit/rplwriter_test.cpp rename to cunit/cuReWriter.cpp index 71de3b6..67e2389 100644 --- a/cunit/rplwriter_test.cpp +++ b/cunit/cuReWriter.cpp @@ -1,6 +1,6 @@ /* * rplwriter_test.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -14,13 +14,12 @@ */ #include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" /** * @brief Unit test for ReStringUtil. */ -class TestRplWriter : public ReTest { +class TestReWriter : public ReTest { public: - TestRplWriter() : ReTest("ReWriter") {} + TestReWriter() : ReTest("ReWriter") { doIt(); } private: void testFileWriter(){ @@ -39,13 +38,12 @@ private: } public: - virtual void doIt(void) { + virtual void run(void) { testFileWriter(); } }; -void testRplWriter() { - TestRplWriter test; - test.run(); +void testReWriter() { + TestReWriter test; } diff --git a/cunit/main.cpp b/cunit/main.cpp deleted file mode 100644 index 0922b20..0000000 --- a/cunit/main.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * main.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -#include "../rplcore/rplcore.hpp" -#include "../rplmath/rplmath.hpp" - -#include - -void testCore(){ - extern void testReString(); - testReString(); - - extern void testReCharPtrMap(); - testReCharPtrMap(); - - extern void testRplWriter(); - testRplWriter(); - - extern void testRplByteStorage(); - testRplByteStorage(); - - extern void testRplQString(); - testRplQString(); - - extern void testReString(); - testReString(); - - extern void testRplException(); - testRplException(); -} - -void testExpr(){ - extern void testRplMFParser(); - testRplMFParser(); - - extern void testRplBenchmark(); - //testRplBenchmark(); - - extern void testReVM(); - testReVM(); - - extern void testReSource(); - testReSource(); - - extern void testRplLexer(); - testRplLexer(); - - extern void testRplMFParser(); - testRplMFParser(); - - extern void testReASTree(); - testReASTree(); - - extern void testReVM(); - testReVM(); - -} - -void testStandard(){ - testExpr(); - testCore(); - extern void testRplMatrix(); - testRplMatrix(); - -} - -void labor(){ -} - -int main(int argc, char *argv[]) -{ - //labor(); - if (argc > 1) - printf("not used: %s\n", argv[1]); - - testStandard(); - -} diff --git a/cunit/rplqstring_test.cpp b/cunit/rplqstring_test.cpp deleted file mode 100644 index d6116f5..0000000 --- a/cunit/rplqstring_test.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * rplqstring_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -/** @file - * @brief Unit test of the ReString tools. - */ - -#include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplQString : public ReTest { -public: - TestRplQString() : - ReTest("ReQString") - {} - -public: - void testLengthOfUInt64(){ - quint64 value = -3; - checkEqu(1, ReQString::lengthOfUInt64(ReString("0"), 0, 10, &value)); - checkEqu(0LL, value); - checkEqu(3, ReQString::lengthOfUInt64("x432", 1, 10, &value)); - checkEqu(432LL, value); - checkEqu(3, ReQString::lengthOfUInt64("x432 x", 1, 10, &value)); - checkEqu(432LL, value); - checkEqu(3, ReQString::lengthOfUInt64("x432fabc x", 1, 10, &value)); - checkEqu(432LL, value); - checkEqu(16, ReQString::lengthOfUInt64("a1234567890123567", 1, 10, &value)); - checkEqu(1234567890123567LL, value); - checkEqu(10, ReQString::lengthOfUInt64("x1234abcdef", 1, 16, &value)); - checkEqu(0x1234abcdefLL, value); - checkEqu(3, ReQString::lengthOfUInt64("432", 0, 8, &value)); - checkEqu(0432LL, value); - checkEqu(6, ReQString::lengthOfUInt64(" 765432 ", 1, 8, &value)); - checkEqu(0765432LL, value); - - checkEqu(0, ReQString::lengthOfUInt64("1 ", 1, 8, &value)); - checkEqu(0, ReQString::lengthOfUInt64("", 1, 8, &value)); - } - void testLengthOfUInt(){ - uint value = 3; - checkEqu(1, ReQString::lengthOfUInt(ReString("0"), 0, 10, &value)); - checkEqu(0, value); - checkEqu(3, ReQString::lengthOfUInt("x432", 1, 10, &value)); - checkEqu(432, value); - checkEqu(3, ReQString::lengthOfUInt("x432 x", 1, 10, &value)); - checkEqu(432, value); - checkEqu(3, ReQString::lengthOfUInt("x432fabc x", 1, 10, &value)); - checkEqu(432, value); - checkEqu(3, ReQString::lengthOfUInt("432", 0, 8, &value)); - checkEqu(0432, value); - checkEqu(6, ReQString::lengthOfUInt(" 765432 ", 1, 8, &value)); - checkEqu(0765432, value); - - checkEqu(0, ReQString::lengthOfUInt("1 ", 1, 8, &value)); - checkEqu(0, ReQString::lengthOfUInt("", 1, 8, &value)); - } - void testLengthOfReal(){ - qreal value; - checkEqu(4, ReQString::lengthOfReal(ReString("0.25"), 0, &value)); - checkEqu(0.25, value); - checkEqu(3, ReQString::lengthOfReal(ReString("X.25"), 1, &value)); - checkEqu(0.25, value); - checkEqu(1, ReQString::lengthOfReal(ReString(" 0"), 1, &value)); - checkEqu(0.0, value); - checkEqu(17, ReQString::lengthOfReal(ReString("X12345678901234567"), 1, &value)); - checkEqu(12345678901234567.0, value); - checkEqu(2, ReQString::lengthOfReal(ReString(".5"), 0, &value)); - checkEqu(0.5, value); - checkEqu(5, ReQString::lengthOfReal(ReString("2.5e2x"), 0, &value)); - checkEqu(250.0, value); - checkEqu(6, ReQString::lengthOfReal(ReString("2.5e+2"), 0, &value)); - checkEqu(250.0, value); - checkEqu(7, ReQString::lengthOfReal(ReString("2.5E-33"), 0, &value)); - checkEqu(2.5e-33, value); - - checkEqu(3, ReQString::lengthOfReal(ReString("2.5E"), 0, &value)); - checkEqu(2.5, value); - checkEqu(3, ReQString::lengthOfReal(ReString("2.5E+"), 0, &value)); - checkEqu(2.5, value); - checkEqu(3, ReQString::lengthOfReal(ReString("2.5E-a"), 0, &value)); - checkEqu(2.5, value); - } - - void testValueOfHexDigit(){ - checkEqu(0, ReQString::valueOfHexDigit('0')); - checkEqu(9, ReQString::valueOfHexDigit('9')); - checkEqu(10, ReQString::valueOfHexDigit('a')); - checkEqu(15, ReQString::valueOfHexDigit('f')); - checkEqu(10, ReQString::valueOfHexDigit('A')); - checkEqu(15, ReQString::valueOfHexDigit('F')); - - checkEqu(-1, ReQString::valueOfHexDigit('0' - 1)); - checkEqu(-1, ReQString::valueOfHexDigit('9' + 1)); - checkEqu(-1, ReQString::valueOfHexDigit('A' - 1)); - checkEqu(-1, ReQString::valueOfHexDigit('F' + 1)); - checkEqu(-1, ReQString::valueOfHexDigit('a' - 1)); - checkEqu(-1, ReQString::valueOfHexDigit('f' + 1)); - } - void testUtf8(){ - ReString name = "Heinz Müller"; - char buffer[32]; - checkEqu("Heinz Müller", ReQString::utf8(name, buffer, sizeof buffer)); - memset(buffer, 'x', sizeof buffer); - checkEqu("Heinz", ReQString::utf8(name, buffer, (size_t) (5+1))); - checkEqu(buffer[6], 'x'); - } - - virtual void doIt(void) { - testUtf8(); - testLengthOfUInt64(); - testLengthOfUInt(); - testLengthOfReal(); - testValueOfHexDigit(); - } -}; -void testRplQString() { - TestRplQString test; - test.run(); -} - diff --git a/expr/ReLexer.cpp b/expr/ReLexer.cpp index 3aab121..e9d814b 100644 --- a/expr/ReLexer.cpp +++ b/expr/ReLexer.cpp @@ -794,13 +794,13 @@ ReToken*ReLexer::scanString(){ throw ReLexException(*m_currentPosition, "missing hexadecimal digit behind \\x"); cc = m_input[length++]; - int hexVal = ReQString::valueOfHexDigit(cc); + int hexVal = ReQStringUtil::valueOfHexDigit(cc); if (hexVal < 0) throw ReLexException(*m_currentPosition, "not a hexadecimal digit behind \\x: %lc", QChar(cc)); if (length < inputLength){ cc = m_input[length]; - int nibble = ReQString::valueOfHexDigit(cc); + int nibble = ReQStringUtil::valueOfHexDigit(cc); if (nibble >= 0){ length++; hexVal = hexVal * 16 + nibble; diff --git a/net/ReTCPClient.hpp b/net/ReTCPClient.hpp index 7321dd3..1fabfe5 100644 --- a/net/ReTCPClient.hpp +++ b/net/ReTCPClient.hpp @@ -11,6 +11,13 @@ #ifndef RETCPCLIENT_HPP #define RETCPCLIENT_HPP +#ifndef REBASE_HPP +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +#endif + + class ReTCPPeer; class RplTcpClient: public QObject { diff --git a/net/ReTCPPeer.hpp b/net/ReTCPPeer.hpp index 578d196..c236037 100644 --- a/net/ReTCPPeer.hpp +++ b/net/ReTCPPeer.hpp @@ -11,6 +11,12 @@ #ifndef RPLTCPPEER_HPP #define RPLTCPPEER_HPP +#ifndef REBASE_HPP +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +#endif + class ReTCPPeer: public QObject { Q_OBJECT public: diff --git a/net/ReTCPServer.hpp b/net/ReTCPServer.hpp index 06c2fb8..4b9d149 100644 --- a/net/ReTCPServer.hpp +++ b/net/ReTCPServer.hpp @@ -1,6 +1,6 @@ /* * ReTCPServer.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -11,6 +11,12 @@ #ifndef RPLTCPSERVER_HPP #define RPLTCPSERVER_HPP +#ifndef REBASE_HPP +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +#endif + // the sources generated from QT include this file directly: #ifndef RPLNET_HPP #include "renet.hpp" diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp new file mode 100644 index 0000000..e9b4d39 --- /dev/null +++ b/os/ReTraverser.cpp @@ -0,0 +1,989 @@ +/* + * ReTraverser.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" +#include "os/reos.hpp" +#if defined __WIN32__ +#include "accctrl.h" +#include "aclapi.h" +#pragma comment(lib, "advapi32.lib") +#endif + +enum { + LC_RIGHTS_AS_STRING_1 = LOC_FIRST_OF(LOC_TRAVERSER), // 50401 + LC_RIGHTS_AS_STRING_2, // 50402 + LC_RIGHTS_AS_STRING_3, // 50403 + LC_GET_PRIVILEGE_1, // 50404 + LC_GET_PRIVILEGE_2, // 50405 + LC_GET_PRIVILEGE_3, // 50406 + LC_GET_FILE_OWNER_1, // 50407 + LC_GET_FILE_OWNER_2, // 50408 +}; + +int ReDirEntryFilter::m_serialId = buildSerialId(CLASSID_DIR_ENTRY_FILTER, 1); + +/** + * Constructor. + */ +ReDirStatus_t::ReDirStatus_t(ReLogger* logger) : + m_path(), + m_fullName(), + m_passNo(0), + m_logger(logger), +#ifdef __linux__ + m_handle(NULL), + m_data(NULL) +//m_status; +#elif defined WIN32 +m_handle(INVALID_HANDLE_VALUE), +//m_data; +m_getPrivilege(true) +#endif +{ +#ifdef __linux__ + memset(&m_status, 0, sizeof m_status); +#elif defined WIN32 + memset(&m_data, 0, sizeof m_data); +#endif +} + +/** + * Returns the last access time. + * + * @return the last access time + */ +const ReFileTime_t* ReDirStatus_t::accessed() { +#ifdef __linux__ + return &(getStatus()->st_atim); +#elif defined __WIN32__ + return &m_data.ftLastAccessTime; +#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 file time as a string. + * + * @param buffer OUT: the file time + * @return buffer.str() (for chaining) + */ +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(); +} + +/** + * Converts a filetime to a unix time (seconds since the Epoche). + * + * @param filetime the filetime to convert + * @return the count of seconds since 1.1.1970 + */ +time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime) { +#ifdef __linux__ + return filetime->tv_sec; +#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 +} + +/** + * Loads the info about the first file into the instance. + * + * @return true: success + */ +bool ReDirStatus_t::findFirst() { + bool rc = false; +#if defined __linux__ + if (m_handle != NULL) + closedir(m_handle); + m_handle = opendir(m_path.str()); + rc = m_handle != NULL && (m_data = readdir(m_handle)) != NULL; + m_status.st_ino = 0; +#elif defined __WIN32__ + if (m_handle != INVALID_HANDLE_VALUE) + FindClose(m_handle); + ReByteBuffer thePath(m_path); + thePath.append(m_path.lastChar() == '\\' ? "*" : "\\*"); + m_handle = FindFirstFileA(thePath.str(), &m_data); + rc = m_handle != INVALID_HANDLE_VALUE; +#endif + m_fullName.setLength(0); + return rc; +} + +/** + * Loads the info about the next file into the instance. + * + * @return true: success + */ +bool ReDirStatus_t::findNext() { +#if defined __linux__ + bool rc = m_handle != NULL && (m_data = readdir(m_handle)) != NULL; + m_status.st_ino = 0; +#elif defined __WIN32__ + bool rc = m_handle != INVALID_HANDLE_VALUE && FindNextFileA(m_handle, &m_data); +#endif + m_fullName.setLength(0); + return rc; +} + +/** + * 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 full filename (with path). + * + * @return the filename with path + */ +const char* ReDirStatus_t::fullName() { + if (m_fullName.length() == 0) + m_fullName.set(m_path).append(node(), -1); + return m_fullName.str(); +} + +#if defined __WIN32__ +/** Gets the name of the file owner. + * + * @param handle file handle (see CreateFile()) + * @param name OUT: the owner: [domain\\]name + * @return true: success + */ +bool ReDirStatus_t::getFileOwner(HANDLE handle, const char* file, + ReByteBuffer& name, ReLogger* logger) { + bool rc = false; + PSID pSidOwner = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + if (GetSecurityInfo(handle, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION, &pSidOwner, NULL, NULL, NULL, &pSD) != ERROR_SUCCESS) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_FILE_OWNER_1, + "GetSecurityInfo($1): $2").arg(file).arg((int) GetLastError()).end(); + } else { + char accountName[128]; + char domainName[128]; + DWORD dwAcctName = sizeof accountName; + DWORD dwDomainName = sizeof domainName; + SID_NAME_USE eUse = SidTypeUnknown; + if (! LookupAccountSid(NULL, pSidOwner, accountName, &dwAcctName, domainName, + &dwDomainName, &eUse)) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_SECURITY, LC_GET_FILE_OWNER_2, + "LookupAccountSid(): $1").arg((int) GetLastError()).end(); + } else { + if (dwDomainName > 0) + name.append(domainName).appendChar('\\'); + name.append(accountName); + rc = true; + } + } + return rc; +} +#endif /* __WIN32__ */ + +#if defined __WIN32__ +/** Tries to get a privilege. + * + * @param privilege the name of the privilege, e.g. "SeBackup" + * @param logger logger for error logging + */ +bool ReDirStatus_t::getPrivilege(const char* privilege, ReLogger* logger) { + bool rc = false; + LUID luidPrivilege; + HANDLE hAccessToken; + if (! OpenProcessToken (GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hAccessToken)) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_PRIVILEGE_1, + "OpenProcessToken(): $1").arg((int) GetLastError()).end(); + } else if (! LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &luidPrivilege)) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_PRIVILEGE_2, + "LookupPrivilegeValue(): $1").arg((int) GetLastError()).end(); + } else { + TOKEN_PRIVILEGES tpPrivileges; + tpPrivileges.PrivilegeCount = 1; + tpPrivileges.Privileges[0].Luid = luidPrivilege; + tpPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (AdjustTokenPrivileges (hAccessToken, FALSE, &tpPrivileges, + 0, NULL, NULL) == 0) + rc = true; + else { + int error = GetLastError(); + if (error != 1300 && logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_PRIVILEGE_3, + "AdjustTokenPrivileges(): $1").arg((int) GetLastError()).end(); + } + } + return rc; +} +#endif /* __WIN32__ */ + +/** + * Tests whether the instance is a directory. + * + * @return true: instance contains the data of a directory + */ +bool ReDirStatus_t::isDirectory() { +#ifdef __linux__ + return m_data->d_type == DT_DIR + || (m_data->d_type == DT_UNKNOWN && S_ISDIR(getStatus()->st_mode)); +#elif defined __WIN32__ + 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. + * + * Unter windows it tests whether the the instance is a reparse point. + * + * @return true: instance contains the data of a link + */ +bool ReDirStatus_t::isLink() { + bool rc; +#ifdef __linux__ + rc = m_data->d_type == DT_LNK + || (m_data->d_type == DT_UNKNOWN && S_ISLNK(getStatus()->st_mode)); +#elif defined __WIN32__ + rc = 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT); +#endif + return rc; +} +/** + * Tests whether the instance is a "normal" file. + * + * @return true: instance contains the data of a not special file + */ +bool ReDirStatus_t::isRegular() { +#ifdef __linux__ + return m_data->d_type == DT_REG + || (m_data->d_type == DT_UNKNOWN && S_ISREG(getStatus()->st_mode)); +#elif defined __WIN32__ + return 0 == (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); +#endif +} +/** + * Returns the modification time. + * + * @return the modification time + */ +const ReFileTime_t* ReDirStatus_t::modified() { +#ifdef __linux__ + return &(getStatus()->st_mtim); +#elif defined __WIN32__ + return &m_data.ftLastWriteTime; +#endif +} + +/** + * Returns the name of the current file (without path). + * + * @return the name of the current file. + */ +const char* ReDirStatus_t::node() const { +#ifdef __linux__ + return m_data->d_name; +#elif defined __WIN32__ + return m_data.cFileName; +#endif +} + +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); + } +} +/** + * Returns the file rights as a string. + * + * @param buffer OUT: the file rights + * @param numerical true: the owner/group should be numerical (UID/GID) + * @param ownerWidth the width for group/owner + * @return buffer.str() (for chaining) + */ +const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer, bool numerical, + int ownerWidth) { + 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__ + const char* name = fullName(); + HANDLE handle = INVALID_HANDLE_VALUE; + if (! isDirectory()) { + if ( (handle = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) + m_logger->sayF(LOG_ERROR | CAT_FILE, LC_RIGHTS_AS_STRING_1, + "CreateFile($1): $2").arg(name).arg((int) GetLastError()).end(); + } else if (m_getPrivilege) { + // we try only one time: + m_getPrivilege = false; + if (getPrivilege(SE_BACKUP_NAME, m_logger)) { + if ( (handle = CreateFile(name, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL)) != INVALID_HANDLE_VALUE) + m_logger->sayF(LOG_ERROR | CAT_FILE, LC_RIGHTS_AS_STRING_2, + "CreateFile($1): $2").arg(name).arg((int) GetLastError()).end(); + } + + } + ReByteBuffer owner; + if (handle != INVALID_HANDLE_VALUE) + getFileOwner(handle, name, owner, m_logger); + CloseHandle(handle); + buffer.appendFix(owner.str(), owner.length(), ownerWidth, ownerWidth); +#endif + return buffer.str(); +} + +/** + * Converts the unix time (time_t) to the file time. + * + * @param time the unix time (secondes since 1.1.1970) + * @param filetime OUT: the OS specific filetime + */ +void ReDirStatus_t::timeToFiletime(time_t time, ReFileTime_t& filetime) { +#ifdef __linux__ + filetime.tv_sec = time; + filetime.tv_nsec = 0; +#elif defined __WIN32__ + LONGLONG ll = Int32x32To64(time, 10000000) + 116444736000000000; + filetime.dwLowDateTime = (DWORD)ll; + 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. + */ +ReDirEntryFilter::ReDirEntryFilter() : + ReSerializable(m_serialId), + m_types(ReDirStatus_t::TC_ALL), + m_nodePatterns(NULL), + m_pathPatterns(NULL), + m_minSize(0), + m_maxSize(-1), + //m_minAge(0), + //m_maxAge(0), + m_minDepth(0), + m_maxDepth(512), + m_allDirectories(false) { + setFiletimeUndef(m_minAge); + setFiletimeUndef(m_maxAge); +} + +/** + * Destructor. + */ +ReDirEntryFilter::~ReDirEntryFilter() { +} + +/** + * Sets the members of the instance from a byte sequence. + * + * @param sequence IN/OUT: the serialized byte sequence + * @param length INT/OUT the length of sequence + */ +void ReDirEntryFilter::deserialize(const uint8_t*& sequence, size_t& length) { + int id; + unpackInt24(sequence, length, id); + if (id != m_serialId) + throw ReSerializeFormatException("wrong serialId", this); + ReByteBuffer buffer; + unpackString64k(sequence, length, buffer); + bool ignoreCase; + unpackBool(sequence, length, ignoreCase); + m_nodePatterns->set(buffer.str(), ignoreCase); + unpackString64k(sequence, length, buffer); + unpackBool(sequence, length, ignoreCase); + unpackString64k(sequence, length, buffer); + m_pathPatterns->set(buffer.str(), ignoreCase); + unpackInt64(sequence, length, m_minSize); + unpackInt64(sequence, length, m_maxSize); + int64_t value; + unpackInt64(sequence, length, value); + unpackBool(sequence, length, m_allDirectories); +} +/** + * Packs the members into a byte sequence. + * + * @param sequence IN/OUT: the place for the byte sequence + */ +ReByteBuffer& ReDirEntryFilter::serialize(ReByteBuffer& sequence) { + sequence.appendBits24(m_serialId); + packString64k(sequence, m_nodePatterns->patternString()); + packBool(sequence, m_nodePatterns->ignoreCase()); + packString64k(sequence, m_pathPatterns->patternString()); + packBool(sequence, m_pathPatterns->ignoreCase()); + sequence.appendBits64(m_minSize); + sequence.appendBits64(m_maxSize); + uint64_t value; +#if defined __linux__ + value = (m_minAge.tv_sec << 32) + m_minAge.tv_nsec; + sequence.appendBits64(int64_t(value)); + value = (m_minAge.tv_sec << 32) + m_minAge.tv_nsec; +#elif defined __WIN32__ +#error "missing impl" +#endif + sequence.appendBits64(int64_t(value)); + packBool(sequence, m_allDirectories); +} + +/** + * Tests whether an entry matches the conditions of the filter. + * + * @param entry entry to test + * @return : the entry matches the conditions of the filter
+ * : otherwise + */ +bool ReDirEntryFilter::match(ReDirStatus_t& entry) { + bool rc = false; + do { + if (m_allDirectories && entry.isDirectory()) { + rc = true; + break; + } + if (0 == (entry.type() & m_types)) + break; + int64_t size = entry.fileSize(); + if (m_minSize > 0 && size < m_minSize) + break; + if (m_maxSize >= 0 && size > m_maxSize) + break; + if (!filetimeIsUndefined(m_minAge) && *entry.modified() > m_minAge) + break; + if (!filetimeIsUndefined(m_maxAge) && m_maxAge > *entry.modified()) + break; + const char* node = entry.node(); + if (m_nodePatterns != NULL && !m_nodePatterns->match(node)) + break; + rc = true; + } while (false); + return rc; +} +; + +#ifdef __linux__ +/** + * Returns the status of the current file (lazy loading). + * + * @return the status of the current file + */ +struct stat* ReDirStatus_t::getStatus() { + if (m_status.st_ino == 0) { + if (stat(fullName(), &m_status) != 0) + m_status.st_ino = 0; + } + return &m_status; +} +#endif + +/** + * Constructor. + */ +ReDirTreeStatistic::ReDirTreeStatistic() : + m_directories(0), + m_files(0), + m_sizes(0ll) { +} +/** + * Builds a string describing the data. + * + * @param buffer IN/OUT: a buffer for the result + * @param append true: the string will be appended to the buffer
+ * false: the buffer will be cleared at the beginning + * @param formatFiles the sprintf format for the file count, e.g. "%8d" + * @param formatSized the sprintf format for the MByte format, e.g. "%12.6f" + * @param formatFiles the sprintf format for the directory count, e.g. "%6d" + * @return a human readable string + */ +const char* ReDirTreeStatistic::statisticAsString(ReByteBuffer& buffer, + bool append, const char* formatFiles, const char* formatSizes, + const char* formatDirs) { + if (!append) + buffer.setLength(0); + buffer.appendInt(m_files, formatFiles); + buffer.append(i18n("file(s)")).appendChar(' '); + buffer.append(m_sizes / 1000.0 / 1000, formatSizes); + buffer.append(" ", 1).append(i18n("MByte")).appendChar(' '); + buffer.appendInt(m_directories, formatDirs); + buffer.append(i18n("dirs(s)")); + return buffer.str(); +} + +/** + * Constructor. + * + * @param triggerCount efficiency: only every N calls a time check takes place + * @param interval the minimum number of seconds between two traces + */ +ReTraceUnit::ReTraceUnit(int triggerCount, int interval) : + m_count(0), + m_triggerCount(triggerCount), + m_lastTrace(0), + m_interval(interval), + m_startTime(time(NULL)) { + m_lastTrace = m_startTime; +} +/** + * Destructor. + */ +ReTraceUnit::~ReTraceUnit() { +} + +/** + * Prints a message. + * + * Often overwritten by a subclass. + * + * @param message message for the trace + * @return true (for chaining) + */ +bool ReTraceUnit::trace(const char* message) { + printf("%s\n", message); + return true; +} + +/** + * Constructor. + * + * @param base the base directory. The traversal starts at this point + */ +ReTraverser::ReTraverser(const char* base, ReTraceUnit* tracer, + ReLogger* logger) : + ReDirTreeStatistic(), + m_minLevel(0), + m_maxLevel(512), + m_level(-1), + m_base(base), + // m_dirs + m_passNoForDirSearch(2), + m_dirPatterns(NULL), + m_tracer(tracer), + m_logger(logger) { + memset(m_dirs, 0, sizeof m_dirs); + m_dirs[0] = new ReDirStatus_t(m_logger); + // remove a preceeding "./". This simplifies the pattern expressions: + if (m_base.startsWith( + ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())) { + m_base.remove(0, 2); + } +} + +/** + * Destructor. + */ +ReTraverser::~ReTraverser() { + destroy(); +} + +/** + * Initializes the instance to process a new base. + * + * @param base the base directory to search + */ +void ReTraverser::changeBase(const char* base) { + destroy(); + m_base.setLength(0).append(base); + memset(m_dirs, 0, sizeof m_dirs); + m_dirs[0] = new ReDirStatus_t(m_logger); + // remove a preceeding "./". This simplifies the pattern expressions: + if (m_base.startsWith( + ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())) { + m_base.remove(0, 2); + } +} + +/** + * Releases the resources. + */ +void ReTraverser::destroy() { + for (size_t ix = 0; ix < sizeof m_dirs / sizeof m_dirs[0]; ix++) { + if (m_dirs[ix] != NULL) { + m_dirs[ix]->freeEntry(); + delete m_dirs[ix]; + m_dirs[ix] = NULL; + } + } +} +/** + * Returns the info about the next file in the directory tree traversal. + * + * @param level OUT: the level relative to the base.
+ * 0 means the file is inside the base.
+ * Not defined if the result is NULL + * @return NULL no more files
+ * otherwise: the stack entry with the next file in the + * directory tree. May be a directory too + */ +ReDirStatus_t* ReTraverser::rawNextFile(int& level) { + ReDirStatus_t* rc = NULL; + bool alreadyRead = false; + bool again; + do { + again = false; + if (m_level < 0) { + // Not yet initialized? + if (m_dirs[0]->m_passNo == 2) + rc = NULL; + else { + // first call: + if (initEntry(m_base.str(), NULL, 0)) { + m_directories++; + if (1 != m_passNoForDirSearch) + rc = m_dirs[0]; + else + again = alreadyRead = true; + } + } + } else { + ReDirStatus_t* current = m_dirs[m_level]; + if (alreadyRead || current->findNext()) { + alreadyRead = false; + // a file or directory found: + if (m_tracer != NULL && m_tracer->isCountTriggered() + && m_tracer->isTimeTriggered()) + m_tracer->trace(current->fullName()); + if (current->m_passNo != m_passNoForDirSearch) { + // we search for any file: + rc = m_dirs[m_level]; + } else { + // we are interested only in true subdirectories: + again = true; + if (m_level < m_maxLevel && current->isDirectory() + && !current->isDotDir() && !current->isLink() + && (m_dirPatterns == NULL + || isAllowedDir(current->node()))) { + // open a new level + alreadyRead = initEntry(current->m_path, + current->node(), m_level + 1); + m_directories++; + } + } + } else { + // the current subdir does not have more files: + if (current->m_passNo == 1) { + // we start the second pass: + alreadyRead = initEntry(current->m_path, NULL, -1); + current->m_passNo = 2; + again = true; + } else { + // this subdirectory is complete. We continue in the parent directory: + current->freeEntry(); + if (--m_level >= 0) { + again = true; + } + } + } + } + if (rc != NULL && rc->isDotDir()) + again = true; + } while (again); + if (rc != NULL && !rc->isDirectory()) { + m_files++; + if (m_sizes >= 0) + m_sizes += rc->fileSize(); + } + level = m_level; + return rc; +} +/** + * Returns the info about the next file matching the filter options. + * + * @param level OUT: the level relative to the base.
+ * 0 means the file is inside the base.
+ * Not defined if the result is NULL + * @param filter NULL: every file matches
+ * otherwise: each found file must match this filter conditions + * @return NULL no more files
+ * otherwise: the info about the next file in the + * directory tree + */ +ReDirStatus_t* ReTraverser::nextFile(int& level, ReDirEntryFilter* filter) { + ReDirStatus_t* rc = rawNextFile(level); + while (rc != NULL) { + if (filter == NULL || filter->match(*rc)) { + break; + } + rc = rawNextFile(level); + } + return rc; +} + +/** + * Initializes an entry in the directory entry stack. + * + * @param parent the parent directory of the entry + * @param node the name of the directory belonging to the entry (without path) + * @param level the index of the entry in the stack.
+ * If < 0: m_levels and m_path will not be changed + * @return true: a new file is available
+ * false/code>: findFirstEntry() signals: no entry. + */ +bool ReTraverser::initEntry(const ReByteBuffer& parent, const char* node, + int level) { + bool rc = false; + if (level < MAX_ENTRY_STACK_DEPTH) { + if (level >= 0) + m_level = level; + if (m_dirs[m_level] == NULL) + m_dirs[m_level] = new ReDirStatus_t(m_logger); + ReDirStatus_t* current = m_dirs[m_level]; + current->m_passNo = 1; + if (level >= 0) { + current->m_path.set(parent.str(), parent.length()); + if (!parent.endsWith(OS_SEPARATOR)) + current->m_path.append(OS_SEPARATOR); + if (node != NULL) + current->m_path.append(node).append(OS_SEPARATOR); + } + rc = current->findFirst(); + } + return rc; +} + +/** + * Sets some properties from a filter. + * + * @param filter the filter with the properties to set + */ +void ReTraverser::setPropertiesFromFilter(ReDirEntryFilter* filter) { + m_minLevel = filter->m_minDepth; + m_maxLevel = filter->m_maxDepth; + setDirPattern(filter->m_pathPatterns); +} + +/** + * Returns the info of an entry the directory stack. + * + * @param offsetFromTop 0: return the top of stack
+ * 1: returns the entry one below the top
+ * 2: ... + * @return NULL: not available
+ * otherwise: the wanted entry + */ +ReDirStatus_t* ReTraverser::topOfStack(int offsetFromTop) { + ReDirStatus_t* rc = NULL; + if (offsetFromTop >= 0 && m_level - 1 - offsetFromTop >= 0) + rc = m_dirs[m_level - 1 - offsetFromTop]; + return rc; +} diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp new file mode 100644 index 0000000..241b913 --- /dev/null +++ b/os/ReTraverser.hpp @@ -0,0 +1,290 @@ +/* + * ReTraverser.hpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#ifndef OS_RETRAVERSER_HPP_ +#define OS_RETRAVERSER_HPP_ + +#include "string/ReMatcher.hpp" +#ifdef __linux__ +#include +#include + +typedef DIR* FindFileHandle_t; +#endif +/** Returns whether a filetime is undefined. + * @param time the filetime to test + * @return true: the given filetime is undefined + */ +inline bool filetimeIsUndefined(ReFileTime_t& time) { +#if defined __linux__ + return time.tv_sec == 0 && time.tv_nsec == 0; +#elif defined __WIN32__ + return time.dwHighDateTime == 0 && time.dwLowDateTime == 0; +#endif +} +/** Sets the filetime to undefined. + * @param time the filetime to clear + */ +inline void setFiletimeUndef(ReFileTime_t& time) { +#if defined __linux__ + time.tv_sec = time.tv_nsec = 0; +#elif defined __WIN32__ + time.dwHighDateTime = time.dwLowDateTime = 0; +#endif +} + +class ReDirStatus_t { +public: + enum Type_t { + TF_UNDEF = 0, + // single property flags: + TF_SUBDIR = 1 << 0, + TF_REGULAR = 1 << 1, + TF_LINK = 1 << 2, + TF_LINK_DIR = 1 << 3, + TF_BLOCK = 1 << 4, + TF_PIPE = 1 << 5, + TF_CHAR = 1 << 6, + TF_SOCKET = 1 << 7, + TF_OTHER = 1 << 8, + // collections: + TC_SPECIAL = (TF_BLOCK | TF_CHAR | TF_SOCKET | TF_PIPE | TF_OTHER), + TC_NON_DIR = (TC_SPECIAL | TF_LINK | TF_REGULAR), + TC_ALL = (TF_SUBDIR | TC_NON_DIR | TF_LINK_DIR) + }; + +public: + ReDirStatus_t(ReLogger* logger); +public: + const ReFileTime_t* accessed(); + ReFileSize_t fileSize(); + const char* filetimeAsString(ReByteBuffer& buffer); + bool findFirst(); + bool findNext(); + void freeEntry(); + const char* fullName(); + bool isDirectory(); + bool isDotDir() const; + bool isLink(); + bool isRegular(); + const ReFileTime_t* modified(); + const char* node() const; + const char* rightsAsString(ReByteBuffer& buffer, bool numerical, + int ownerWidth); + Type_t type(); + char typeAsChar(); +public: + static const char* filetimeToString(const ReFileTime_t* time, + ReByteBuffer& buffer); + static time_t filetimeToTime(const ReFileTime_t* time); +#if defined __WIN32__ + static bool getFileOwner(HANDLE handle, const char* file, ReByteBuffer& name, + ReLogger* logger = NULL); + static bool getPrivilege(const char* privilege, ReLogger* logger); +#endif + static void timeToFiletime(time_t time, ReFileTime_t& filetime); +public: + ReByteBuffer m_path; + ReByteBuffer m_fullName; + int m_passNo; + ReLogger* m_logger; +#ifdef __linux__ + DIR* m_handle; + struct dirent* m_data; + struct stat m_status; +public: + struct stat* getStatus(); +#elif defined WIN32 + HANDLE m_handle; + WIN32_FIND_DATAA m_data; + bool m_getPrivilege; +#endif +}; +class ReDirEntryFilter: public ReSerializable { +public: + ReDirEntryFilter(); + ~ReDirEntryFilter(); +public: + virtual void deserialize(const uint8_t*& sequence, size_t& length); + bool match(ReDirStatus_t& entry); + virtual ReByteBuffer& serialize(ReByteBuffer& sequence); +public: + ReDirStatus_t::Type_t m_types; + RePatternList* m_nodePatterns; + RePatternList* m_pathPatterns; + ReFileSize_t m_minSize; + ReFileSize_t m_maxSize; + ReFileTime_t m_minAge; + ReFileTime_t m_maxAge; + int m_minDepth; + int m_maxDepth; + bool m_allDirectories; +private: + static int m_serialId; +}; + +class ReTraceUnit { +public: + ReTraceUnit(int m_triggerCount = 10, int interval = 60); + virtual ~ReTraceUnit(); +public: + /** Returns whether the the instance is triggered. + * To avoid too the not cheap call of time() the trace unit uses a counter. + * If the counter reaches a given level the time check should be done. + * @return true: the counter has reached m_triggerCount + */ + inline bool isCountTriggered() { + bool rc = ++m_count % m_triggerCount == 0; + return rc; + } + /** Tests whether a given waiting time has been gone since the last trace. + * @return true: the last trace has been done after + * at least m_interval seconds + */ + inline bool isTimeTriggered() { + time_t now = time(NULL); + bool rc = now - m_lastTrace > m_interval; + if (rc) { + m_lastTrace = now; + } + return rc; + } + virtual bool trace(const char* message); +protected: + int m_count; + int m_triggerCount; + time_t m_lastTrace; + int m_interval; + time_t m_startTime; +}; + +class ReDirTreeStatistic { +public: + ReDirTreeStatistic(); +public: + const char* statisticAsString(ReByteBuffer& buffer, bool append = false, + const char* formatFiles = "%8d ", const char* formatSizes = "%12.6f", + const char* formatDirs = "%7d "); + /** + * Resets the counters. + */ + inline void clear() { + m_files = m_directories = 0; + m_sizes = 0ll; + } +public: + int m_directories; + int m_files; + int64_t m_sizes; +}; + +#define MAX_ENTRY_STACK_DEPTH 256 +class ReTraverser: public ReDirTreeStatistic { +public: + ReTraverser(const char* base, ReTraceUnit* tracer = NULL, ReLogger* logger = + NULL); + virtual ~ReTraverser(); +public: + void changeBase(const char* base); + /** + * Return the number of entered directories . + * @return the number of directories entered until now + */ + inline int directories() const { + return m_directories; + } + /** + * Return the number of found files. + * @return the number of files found until now + */ + inline int files() const { + return m_files; + } + /** Returns whether the current directory has changed since the last call. + * @param state IN/OUT: stored info about the current directory. + * The value has no interest for the caller + * @return true: the path has been changed + */ + inline bool hasChangedPath(int& state) { + bool rc = m_directories > state; + state = m_directories; + return rc; + } + ReDirStatus_t* rawNextFile(int& level); + ReDirStatus_t* nextFile(int& level, ReDirEntryFilter* filter = NULL); + /** Sets the tree traversal algorithm. + * @param depthFirst true: files of the subdirectories will + * be returned earlier + */ + void setDepthFirst(bool depthFirst) { + m_passNoForDirSearch = depthFirst ? 1 : 2; + } + /** Sets directory filter (pattern list). + * @param pattern pattern list for the subdirs to be entered + */ + inline void setDirPattern(RePatternList* pattern) { + m_dirPatterns = pattern; + if (pattern != NULL) + m_dirPatterns->setIgnoreCase(true); + } + /** Sets the maximal depth. + * @param value the value to set + */ + inline void setMaxLevel(int value) { + m_maxLevel = value; + } + /** Sets the minimal depth. + * @param value the value to set + */ + inline void setMinLevel(int value) { + m_minLevel = value; + } + void setPropertiesFromFilter(ReDirEntryFilter* filter); + /** + * Return the sum of file lengths of the found files. + * @return the sum of file lengths of the files found until now + */ + inline int64_t sizes() const { + return m_sizes; + } + ReDirStatus_t* topOfStack(int offset = 0); +protected: + void destroy(); + void freeEntry(int level); + bool initEntry(const ReByteBuffer& parent, const char* node, int level); + /** + * Tests whether a directory should be processed. + * @param node the base name of the subdir + * @return true: the subdir will be processed
+ * false: do not enter this subdir + */ + inline bool isAllowedDir(const char* node) { + bool rc = m_dirPatterns->match(node); + return rc; + } +protected: + int m_minLevel; + int m_maxLevel; + int m_level; + ReByteBuffer m_base; + ReDirStatus_t* m_dirs[MAX_ENTRY_STACK_DEPTH]; + /// each directory will be passed twice: for all files + for directories only + /// 1: depth first 2: breadth first + int m_passNoForDirSearch; + /// a subdirectory will be entered only if this pattern list matches + /// if NULL any directory will be entered + RePatternList* m_dirPatterns; + ReDirTreeStatistic m_statistic; + ReTraceUnit* m_tracer; + ReLogger* m_logger; +}; + +#endif /* OS_RETRAVERSER_HPP_ */ diff --git a/os/reos.hpp b/os/reos.hpp new file mode 100644 index 0000000..342a9f1 --- /dev/null +++ b/os/reos.hpp @@ -0,0 +1,48 @@ +/* + * reos.hpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#ifndef OS_REOS_HPP_ +#define OS_REOS_HPP_ + +#if defined __linux__ +#include "unistd.h" +#include +#include +#include +#elif defined __WIN32__ +#include +#include "windows.h" +#include +#else +#error "unknown os" +#endif + +/** Returns whether a time is greater (younger) than another. + * @param time1 first operand + * @param time2 second operand + * @return true: time1 > time2 + */ +inline bool operator >(const ReFileTime_t& time1, const ReFileTime_t& time2) { +#if defined __linux__ + return time1.tv_sec > time2.tv_sec + || (time1.tv_sec == time2.tv_sec && time1.tv_nsec > time2.tv_nsec); +#else + return time1.dwHighDateTime > time2.dwHighDateTime + || (time1.dwHighDateTime == time2.dwHighDateTime + && time1.dwLowDateTime > time2.dwLowDateTime); +#endif +} +#include "os/ReTraverser.hpp" +#include "os/ReDirTools.hpp" +#include "net/renet.hpp" +#include "os/ReRemoteDir.hpp" + +#endif /* OS_REOS_HPP_ */ diff --git a/remodules.hpp b/remodules.hpp index ea53cad..ecc71cc 100644 --- a/remodules.hpp +++ b/remodules.hpp @@ -1,6 +1,6 @@ /* * remodules.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -23,6 +23,7 @@ enum { LOC_SOURCE, LOC_VM, LOC_MFPARSER, // 115 + LOC_TRAVERSER, }; #define LOC_FIRST_OF(moduleNo) (moduleNo*100+1) class RplModules { diff --git a/static/rplstaticlib.cpp b/static/ReStaticLib.cpp similarity index 79% rename from static/rplstaticlib.cpp rename to static/ReStaticLib.cpp index 0dc5255..487cb56 100644 --- a/static/rplstaticlib.cpp +++ b/static/ReStaticLib.cpp @@ -1,6 +1,6 @@ /* * rplstaticlib.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -10,9 +10,7 @@ */ -#include "../static/rplstaticlib.hpp" - - -RplStaticLib::RplStaticLib() -{ +int main(int argc, char** argv){ + void allTests(); + allTests(); } diff --git a/static/rplstatic.pro b/static/rplstatic.pro index 82c9e9b..1ab5aa3 100644 --- a/static/rplstatic.pro +++ b/static/rplstatic.pro @@ -8,9 +8,9 @@ QT += network testlib QT -= gui -TARGET = rplstatic -TEMPLATE = lib -CONFIG += staticlib +TARGET = ReStaticLib +#TEMPLATE = lib +#CONFIG += staticlib INCLUDEPATH = .. /usr/include/c++/4.9 @@ -22,6 +22,9 @@ SOURCES += \ ../base/ReStringUtil.cpp \ ../base/ReTerminator.cpp \ ../base/ReTest.cpp \ + ../base/ReByteStorage.cpp \ + ../base/ReWriter.cpp \ + ../base/ReCharPtrMap.cpp \ ../math/ReEnigma.cpp \ ../math/ReMatrix.cpp \ ../math/ReRandom.cpp \ @@ -31,15 +34,31 @@ SOURCES += \ ../net/ReTCPServer.cpp \ ../expr/ReLexer.cpp \ ../expr/ReSource.cpp \ - ../base/ReQString.cpp \ + ../base/ReQStringUtil.cpp \ ../expr/ReASTree.cpp \ ../expr/ReASClasses.cpp \ ../expr/ReMFParser.cpp \ ../expr/ReVM.cpp \ ../expr/ReParser.cpp \ - ../base/ReByteStorage.cpp \ - ../base/ReWriter.cpp \ - ../base/ReCharPtrMap.cpp + ../bench/cppbench.cpp \ + ../cunit/cuReConfig.cpp \ + ../cunit/cuReContainer.cpp \ + ../cunit/cuReEnigma.cpp \ + ../cunit/cuReASTree.cpp \ + ../cunit/cuReBench.cpp \ + ../cunit/cuReByteStorage.cpp \ + ../cunit/cuReCharPtrMap.cpp \ + ../cunit/cuReException.cpp \ + ../cunit/cuReLexer.cpp \ + ../cunit/cuReMatrix.cpp \ + ../cunit/cuReQStringUtil.cpp \ + ../cunit/cuReSource.cpp \ + ../cunit/cuReStringUtil.cpp \ + ../cunit/cuReVM.cpp \ + ../cunit/cuReWriter.cpp \ + ../cunit/allTests.cpp \ + ReStaticLib.cpp \ + ../cunit/cuReMFParser.cpp HEADERS += ../remodules.hpp \ ../base/ReConfig.hpp \ @@ -63,7 +82,7 @@ HEADERS += ../remodules.hpp \ ../expr/ReLexer.hpp \ ../expr/reexpr.hpp \ ../expr/ReSource.hpp \ - ../base/ReQString.hpp \ + ../base/ReQStringUtil.hpp \ ../expr/ReASTree.hpp \ ../expr/ReASClasses.hpp \ ../expr/ReMFParser.hpp \ @@ -71,7 +90,8 @@ HEADERS += ../remodules.hpp \ ../expr/ReParser.hpp \ ../base/ReByteStorage.hpp \ ../base/ReWriter.hpp \ - ../base/ReCharPtrMap.hpp + ../base/ReCharPtrMap.hpp \ + ../base/ReQStringUtil.hpp unix:!symbian { maemo5 { diff --git a/static/rplstaticlib.hpp b/static/rplstaticlib.hpp deleted file mode 100644 index ce4f2e3..0000000 --- a/static/rplstaticlib.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * rplstaticlib.hpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - - -#ifndef RPLSTATICLIB_HPP -#define RPLSTATICLIB_HPP - - -class RplStaticLib -{ - -public: - RplStaticLib(); -}; - -#endif // RPLSTATICLIB_HPP -- 2.39.5