]> gitweb.hamatoma.de Git - reqt/commitdiff
allTests works, ReUnitParser works
authorhama <hama@siduction.net>
Mon, 6 Apr 2015 01:41:50 +0000 (03:41 +0200)
committerhama <hama@siduction.net>
Mon, 6 Apr 2015 01:41:50 +0000 (03:41 +0200)
56 files changed:
appl/qfilesearch [deleted submodule]
appl/refind [new submodule]
base/ReContainer.cpp
base/ReQString.cpp [deleted file]
base/ReQStringUtil.cpp [new file with mode: 0644]
base/ReQStringUtil.hpp [new file with mode: 0644]
base/ReQtring.hpp [deleted file]
base/ReTerminator.hpp
base/ReTest.cpp
base/ReTest.hpp
base/rebase.hpp
base/testrplexample.cpp
cunit/allTests.cpp [new file with mode: 0644]
cunit/cuReASTree.cpp [new file with mode: 0644]
cunit/cuReBench.cpp [new file with mode: 0644]
cunit/cuReByteStorage.cpp [new file with mode: 0644]
cunit/cuReCharPtrMap.cpp [new file with mode: 0644]
cunit/cuReConfig.cpp
cunit/cuReContainer.cpp
cunit/cuReEnigma.cpp
cunit/cuReException.cpp [new file with mode: 0644]
cunit/cuReLexer.cpp [new file with mode: 0644]
cunit/cuReMFParser.cpp [new file with mode: 0644]
cunit/cuReMatrix.cpp [new file with mode: 0644]
cunit/cuReQStringUtil.cpp [new file with mode: 0644]
cunit/cuReSource.cpp [new file with mode: 0644]
cunit/cuReStringUtil.cpp [new file with mode: 0644]
cunit/cuReTraverser.cpp [new file with mode: 0644]
cunit/cuReVM.cpp [new file with mode: 0644]
cunit/cuReWriter.cpp [new file with mode: 0644]
cunit/main.cpp [deleted file]
cunit/rplastree_test.cpp [deleted file]
cunit/rplbench.cpp [deleted file]
cunit/rplbytestorage_test.cpp [deleted file]
cunit/rplcharptrmap_test.cpp [deleted file]
cunit/rplexception_test.cpp [deleted file]
cunit/rpllexer_test.cpp [deleted file]
cunit/rplmatrix_test.cpp [deleted file]
cunit/rplmfparser_test.cpp [deleted file]
cunit/rplqstring_test.cpp [deleted file]
cunit/rplsource_test.cpp [deleted file]
cunit/rplstring_test.cpp [deleted file]
cunit/rplvm_test.cpp [deleted file]
cunit/rplwriter_test.cpp [deleted file]
expr/ReLexer.cpp
net/ReTCPClient.hpp
net/ReTCPPeer.hpp
net/ReTCPServer.hpp
os/ReTraverser.cpp [new file with mode: 0644]
os/ReTraverser.hpp [new file with mode: 0644]
os/reos.hpp [new file with mode: 0644]
remodules.hpp
static/ReStaticLib.cpp [new file with mode: 0644]
static/rplstatic.pro
static/rplstaticlib.cpp [deleted file]
static/rplstaticlib.hpp [deleted file]

diff --git a/appl/qfilesearch b/appl/qfilesearch
deleted file mode 160000 (submodule)
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 0000000000000000000000000000000000000000
diff --git a/appl/refind b/appl/refind
new file mode 160000 (submodule)
--- /dev/null
+++ b/appl/refind
@@ -0,0 +1 @@
+Subproject commit 0000000000000000000000000000000000000000
index 6b7e5bf86d078e2c33e24a893be3d3a80c440330..67a439a2097fe01365477da4d0fee3ea941f222c 100644 (file)
@@ -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 (file)
index a57930b..0000000
+++ /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 <code>ReString</code>s.
- */
-/** @file rplcore/rplqstring.hpp
- *
- * @brief Definitions for missed operation for <code>ReString</code>s.
- */
-#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 <code>qstring.toUtf8().constData()</code> 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              <code>buffer</code>
- */
-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 (file)
index 0000000..7dd4c06
--- /dev/null
@@ -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 <code>ReString</code>s.
+ */
+/** @file rplcore/rplqstring.hpp
+ *
+ * @brief Definitions for missed operation for <code>ReString</code>s.
+ */
+#include "base/rebase.hpp"
+#include <QtCore/qmath.h>
+/**
+ * @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 <code>qstring.toUtf8().constData()</code> 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              <code>buffer</code>
+ */
+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<br>
+ *                   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  <code>true</code>: 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<br>
+ *          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              <code>defaultValue</code>: the result was not valid<br>
+ *                      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              <code>defaultValue</code>: the result was not valid<br>
+ *                      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              <code>defaultValue</code>: the result was not valid<br>
+ *                      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<br>
+ *                only units defined in m_unitList are allowed<br>
+ *                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/ReQStringUtil.hpp b/base/ReQStringUtil.hpp
new file mode 100644 (file)
index 0000000..7af38e9
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * ReQtring.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 RPLQSTRING_HPP
+#define RPLQSTRING_HPP
+
+class ReQStringUtil {
+public:
+   static int lengthOfUInt64(const ReString& text, int start = 0,
+      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 =
+      NULL);
+   /**
+    * @brief Returns the value of a hexadecimal digit.
+    *
+    * @param digit     a (unicode) character
+    * @return          -1: not a hexadecimal digit<br>
+    *                  otherwise: the value, e.g. 10 for 'a'
+    */
+   inline static int valueOfHexDigit(int digit){
+      return digit >= '0' && digit <= '9' ? digit - '0' :
+             digit >= 'A' && digit <= 'F' ? digit - 'A' + 10 :
+             digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1;
+   }
+   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/ReQtring.hpp b/base/ReQtring.hpp
deleted file mode 100644 (file)
index 77e1e94..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ReQtring.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 RPLQSTRING_HPP
-#define RPLQSTRING_HPP
-
-class ReQString {
-public:
-   static int lengthOfUInt64(const ReString& text, int start = 0,
-      int radix = 10, quint64* 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 =
-      NULL);
-   /**
-    * @brief Returns the value of a hexadecimal digit.
-    *
-    * @param digit     a (unicode) character
-    * @return          -1: not a hexadecimal digit<br>
-    *                  otherwise: the value, e.g. 10 for 'a'
-    */
-   inline static int valueOfHexDigit(int digit){
-      return digit >= '0' && digit <= '9' ? digit - '0' :
-             digit >= 'A' && digit <= 'F' ? digit - 'A' + 10 :
-             digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1;
-   }
-   static char* utf8(const ReString& source, char buffer[], size_t bufferSize);
-};
-
-#endif // RPLQSTRING_HPP
index d72d6279dd57885450c55dc114ebe04f9dae7c2f..d8a193dee81453169b78b2f3e06a61297a81862f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ReTerminator.hpp
- * 
+ *
  * License: Public Domain
  * You can use and modify this file without any restriction.
  * Do what you want.
index 22253b437a3be245f20c5af420ca078d004db74c..a8f9537da81f8dd17541ea12ff9caf77b1cf3bd5 100644 (file)
@@ -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--;
+    }
 }
 
 /**
index 9b27d01e3e90b4c1a9beac8d1c79feb4fbfa296b..0e85581fc1cce1136340747edfdb352989966ed3 100644 (file)
@@ -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,
index b7cb676ae0b9f2ce5f053fc5c473a21a3aacc170..c8f0d852f5c0329b1222ebe60f7da21465210571 100644 (file)
@@ -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 <stdio.h>
 #include <string.h>
@@ -20,9 +20,6 @@
 #include <errno.h>
 #include <assert.h>
 
-#include <QAbstractSocket>
-#include <QTcpSocket>
-#include <QTcpServer>
 #include <QThread>
 #include <QIODevice>
 #include <QTextStream>
@@ -32,7 +29,7 @@
 #include <QMutex>
 #include <QRegularExpression>
 #include <QtCore/qmath.h>
-
+#include <QTranslator>
 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
index a2206461e0c608343db1c4d68f58a16184c503b1..f4c53dcdb3f63e02d39a0ddd146aa53f4f87fbae 100644 (file)
@@ -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 (file)
index 0000000..dea96b8
--- /dev/null
@@ -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/cuReASTree.cpp b/cunit/cuReASTree.cpp
new file mode 100644 (file)
index 0000000..fde8699
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * rplastree_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 abstract syntax tree.
+ */
+
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+class TestReASTree : public ReTest{
+private:
+    ReSource m_source;
+    ReStringReader m_reader;
+    ReStringSourceUnit m_unit;
+    ReASTree m_tree;
+public:
+    TestReASTree() :
+        ReTest("ReASTree"),
+        m_source(),
+        m_reader(m_source),
+        m_unit("<main>", "", &m_reader),
+        m_tree()
+    {}
+public:
+    void testReASException() {
+        try{
+            m_reader.addSource("<main>", "12");
+            m_source.addReader(&m_reader);
+            m_source.addSourceUnit(m_reader.currentSourceUnit());
+            const ReSourcePosition* pos = m_source.newPosition(2);
+            throw ReASException(pos, "simple string: %s", "Hi");
+            checkF(true);
+        } catch (ReASException exc){
+            checkEqu("<main>:0:2: simple string: Hi", exc.getMessage().constData());
+        }
+    }
+    void testReASVariant(){
+        ReASVariant val1;
+        val1.setFloat(2.5E-2);
+        checkEqu(2.5E-2, val1.asFloat());
+        ReASVariant val2(val1);
+        checkEqu(2.5E-2, val2.asFloat());
+
+        val1.setInt(4321);
+        checkEqu(4321, val1.asInt());
+        val2 = val1;
+        checkEqu(4321, val2.asInt());
+
+        val1.setBool(false);
+        checkF(val1.asBool());
+        val2 = val1;
+        checkF(val2.asBool());
+
+        val1.setBool(true);
+        checkT(val1.asBool());
+        val2 = val1;
+        checkT(val2.asBool());
+
+        val1.setString("High noon!");
+        checkEqu("High noon!", *val1.asString());
+        val2 = val1;
+        val1.setString("Bye");
+        checkEqu("High noon!", *val2.asString());
+        ReASVariant val3(val1);
+        checkEqu("Bye", *val3.asString());
+    }
+    void testReASConstant(){
+        ReASConstant constant;
+        //constant.value().setString("Jonny");
+        ReASVariant value;
+        //constant.calc(value);
+        //checkEqu("Jonny", *value.asString());
+    }
+    void testReASNamedValue(){
+        ReASNamedValue value(NULL, m_tree.symbolSpaces()[0], "gugo",
+                ReASNamedValue::A_GLOBAL);
+        checkEqu("gugo", value.name());
+    }
+    virtual void run() {
+        testReASNamedValue();
+        testReASConstant();
+        testReASException();
+        testReASVariant();
+    }
+};
+void testReASTree() {
+    TestReASTree test;
+}
+
+
+
+
+
+
diff --git a/cunit/cuReBench.cpp b/cunit/cuReBench.cpp
new file mode 100644 (file)
index 0000000..5a87df4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * rplbench.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 abstract syntax tree.
+ */
+
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+class TestRplBenchmark : public ReTest{
+private:
+    const char* m_filename;
+    ReSource m_source;
+    ReFileReader m_reader;
+    ReASTree m_tree;
+public:
+    TestRplBenchmark() :
+        ReTest("RplBenchmark"),
+        m_filename("/home/ws/qt/rplqt/bench/mfbench.mf"),
+        m_source(),
+        m_reader(m_source),
+        m_tree()
+    {
+        m_source.addReader(&m_reader);
+        m_reader.addSource(m_filename);
+    }
+public:
+    void benchmark() {
+        time_t start = time(NULL);
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        time_t end = time(NULL);
+        printf("compilation: %d sec\n", int(end - start));
+    }
+    virtual void run() {
+        try{
+            ReFileSourceUnit* unit = dynamic_cast<ReFileSourceUnit*>
+                    (m_reader.currentSourceUnit());
+            if (unit != NULL && ! unit->isOpen())
+                throw ReException("file not found: %s", m_filename);
+            benchmark();
+        } catch(ReException ex){
+            printf("%s\n", ex.getMessage().constData());
+        }
+    }
+};
+void testRplBenchmark() {
+    TestRplBenchmark test;
+    test.run();
+}
+
+
+
diff --git a/cunit/cuReByteStorage.cpp b/cunit/cuReByteStorage.cpp
new file mode 100644 (file)
index 0000000..fb8cf6d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * rplbytestorage_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 byte and C string storage.
+ */
+
+#include "base/rebase.hpp"
+
+class TestReByteStorage : public ReTest{
+public:
+    TestReByteStorage() :
+        ReTest("ReByteStorage")
+    { doIt(); }
+private:
+    void testChars(){
+        ReByteStorage store(100);
+        char* s1 = store.allocateChars(4);
+        memcpy((void*) s1, "123", 4);
+        const char* s2 = store.allocateChars("abc");
+        const char* s3 = store.allocateChars("defghij", 3);
+        checkEqu(s1, "123");
+        checkEqu(s2, "abc");
+        checkEqu(s3, "def");
+        const char* ptr = s1 + 4;
+        checkT(ptr == s2);
+        ptr += 4;
+        checkT(ptr == s3);
+    }
+
+    void testBytes(){
+        ReByteStorage store(100);
+        uint8_t* s1 = store.allocateBytes(4);
+        memcpy((void*) s1, "1234", 4);
+        uint8_t* s2 = store.allocateBytes((void*) "abcd", 4);
+        uint8_t* s3 = store.allocateBytes((void*) "efghij", 4);
+        uint8_t* s4 = store.allocateZeros(4);
+
+        checkEqu("1234abcdefgh", (const char*) s1);
+        uint8_t* ptr = s1 + 4;
+        checkT(ptr == s2);
+        ptr += 4;
+        checkT(ptr == s3);
+        ptr += 4;
+        checkT(ptr == s4);
+        for (int ii = 0; ii < 4; ii++)
+            checkEqu(0, (int) s4[ii]);
+    }
+    void testBufferChange(){
+        ReByteStorage store(10);
+        char buffer[2];
+        buffer[1] = '\0';
+        for (int ii = 0; ii < 10000; ii++){
+            buffer[1] = 'A' + ii % 26;
+            store.allocateBytes(buffer, 1);
+        }
+        int a = 1;
+    }
+
+public:
+    virtual void run() {
+        testBufferChange();
+        testChars();
+        testBytes();
+    }
+};
+void testReByteStorage() {
+    TestReByteStorage test;
+}
+
+
diff --git a/cunit/cuReCharPtrMap.cpp b/cunit/cuReCharPtrMap.cpp
new file mode 100644 (file)
index 0000000..2d5df72
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * rplcharptrmap_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
+ */
+
+#include "base/rebase.hpp"
+
+class TestReCharPtrMap : public ReTest{
+public:
+    TestReCharPtrMap() :
+        ReTest("ReCharPtrMap")
+    {
+       doIt();
+    }
+protected:
+    void testBasic(){
+        ReCharPtrMap<const char*> map;
+        map["x"] = "x1";
+        checkT(map.contains("x"));
+        checkF(map.contains("y"));
+        checkEqu("x1", map["x"]);
+    }
+public:
+    virtual void run(void) {
+        testBasic();
+    }
+};
+void testReCharPtrMap() {
+    TestReCharPtrMap test;
+}
index 535347d31bec20c4075e625ad7380e9fab5be7db..01daeb59f76dc3857d1229c470f2b5abad185612 100644 (file)
@@ -17,6 +17,7 @@ class TestReConfig: public ReTest {
 public:
     TestReConfig() :
         ReTest("ReConfig") {
+       doIt();
     }
 
 public:
index e418b4e85c0dfee56463712a54fbbee25fd19046..ff368c6a5ad26b7b76c2c2d47d3f1f0ba51cd7c9 100644 (file)
@@ -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 <code>ReContainer</code>
  */
-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;
 }
 
 
index 44912aa1a89bf9cd8837142e6f1b38fbeea2765a..bc07e177a9dfbc8fd684e6194533b5dd27066fdf 100644 (file)
@@ -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 <code>ReEnigma</code>.
  */
 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/cuReException.cpp b/cunit/cuReException.cpp
new file mode 100644 (file)
index 0000000..1230b73
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * rplexception_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
+ */
+#include "base/rebase.hpp"
+
+/** @file
+ * @brief Unit test of the basic exceptions.
+ */
+
+class TestReException : public ReTest{
+public:
+    TestReException() : ReTest("RplException") { doIt(); }
+
+public:
+    void testBasic() {
+        try{
+            throw ReException("simple");
+            checkF(true);
+        } catch (ReException exc){
+            checkEqu("simple", exc.getMessage().constData());
+        }
+        try{
+            throw ReException("String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (ReException exc){
+            checkEqu("String: Hi and int -333", exc.getMessage().constData());
+        }
+        try{
+            throw ReException(LOG_INFO, 1234, &m_memoryLogger,
+                    "String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (ReException exc){
+            checkT(logContains("^ .*\\(1234\\): String: Hi and int -333"));
+        }
+        log("ok");
+    }
+    virtual void run() {
+        testBasic();
+    }
+};
+void testReException() {
+    TestReException test;
+}
+
+
+
diff --git a/cunit/cuReLexer.cpp b/cunit/cuReLexer.cpp
new file mode 100644 (file)
index 0000000..3cdb2ed
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * rpllexer_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 syntax symbol extractor.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+class TestRplLexer : public ReTest, public ReToken{
+public:
+    TestRplLexer() :
+        ReTest("ReLexer"),
+        ReToken(TOKEN_ID)
+    {}
+
+public:
+    void testRplToken(){
+        // test constructor values:
+        checkEqu(TOKEN_ID, tokenType());
+        checkEqu(0, m_value.m_id);
+        checkT(m_string.isEmpty());
+        checkT(m_printableString.isEmpty());
+
+        m_value.m_id = 7422;
+        checkEqu(7422, ReToken::id());
+        m_string = "Wow!";
+        checkEqu("Wow!", ReToken::toString());
+        m_printableString = "GooGoo";
+        checkEqu("GooGoo", rawString());
+        m_tokenType = TOKEN_NUMBER;
+        checkEqu(TOKEN_NUMBER, tokenType());
+
+        clear();
+        checkEqu(TOKEN_UNDEF, tokenType());
+        checkEqu(0, m_value.m_id);
+        checkT(m_string.isEmpty());
+        checkT(m_printableString.isEmpty());
+
+        m_value.m_integer = 773322;
+        checkEqu(773322, asInteger());
+        m_value.m_real = 0.25;
+        checkEqu(0.25, asReal());
+    }
+
+    ReToken* checkToken(ReToken* token, RplTokenType type, int id = 0,
+                    const char* string = NULL){
+        checkEqu(type, token->tokenType());
+        if (id != 0)
+            checkEqu(id, token->id());
+        if (string != NULL)
+            checkEqu(string, token->toString());
+        return token;
+    }
+    enum { KEY_UNDEF, KEY_IF, KEY_THEN, KEY_ELSE, KEY_FI
+         };
+#   define KEYWORDS "if then else fi"
+    enum { OP_UNDEF, OP_PLUS, OP_TIMES, OP_DIV, OP_GT,
+           OP_LT, OP_GE, OP_LE, OP_EQ, OP_ASSIGN, OP_PLUS_ASSIGN, OP_DIV_ASSIGN,
+           OP_TIMES_ASSIGN
+         };
+#   define OPERATORS "+\n* /\n> < >= <= ==\n= += /= *="
+    enum { COMMENT_UNDEF, COMMENT_1, COMMENT_MULTILINE, COMMENT_2
+    };
+#   define COMMENTS "/* */ // \n"
+    void testSpace(){
+        ReSource source;
+        ReStringReader reader(source);
+#       define BLANKS1 "\t\t   \n"
+#       define BLANKS2 " \n"
+        reader.addSource("<main>", BLANKS1 BLANKS2);
+        source.addReader(&reader);
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_DECIMAL,
+                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS1);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS2);
+    }
+    void testNumeric(){
+        ReSource source;
+        ReStringReader reader(source);
+        const char* blanks = "321 0x73 7.8e+5";
+        reader.addSource("<main>", blanks);
+        source.addReader(&reader);
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
+        ReToken* token = checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkEqu(321, token->asInteger());
+        token = checkToken(lex.nextNonSpaceToken(), TOKEN_NUMBER);
+        checkEqu(0x73, token->asInteger());
+        token = checkToken(lex.nextNonSpaceToken(), TOKEN_REAL);
+        checkEqu(7.8e+5, token->asReal());
+    }
+
+    void testOperators(){
+        ReSource source;
+        ReStringReader reader(source);
+        const char* ops = "<< < <<< <= == = ( ) [ ]";
+        reader.addSource("<main>", ops);
+        source.addReader(&reader);
+        enum { UNDEF, SHIFT, LT, SHIFT2, LE, EQ, ASSIGN,
+               LPARENT, RPARENT, LBRACKET, RBRACKET };
+        ReLexer lex(&source, KEYWORDS, ops, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT2);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LE);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, EQ);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, ASSIGN);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
+        reader.addSource("<buffer2>", "(([[");
+        lex.startUnit("<buffer2>");
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
+    }
+
+    void testComments(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "/**/9//\n8/***/7// wow\n/*\n*\n*\n**/");
+        source.addReader(&reader);
+
+        enum { COMMENT_UNDEF, COMMENT_MULTILINE, COMMENT_1
+        };
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
+                   "/**/");
+        checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
+                   "//\n");
+        checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
+                   "/***/");
+        checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
+                   "// wow\n");
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
+                   "/*\n*\n*\n**/");
+    }
+    void testStrings(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "\"abc\\t\\r\\n\\a\\v\"'1\\x9Z\\x21A\\X9'");
+        source.addReader(&reader);
+
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_STRING, '"', "abc\t\r\n\a\v");
+        checkToken(lex.nextToken(), TOKEN_STRING, '\'', "1\tZ!A\t");
+    }
+    void testKeywords(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "if\n\tthen else\nfi");
+        source.addReader(&reader);
+
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_THEN);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_ELSE);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_FI);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
+    }
+
+    void testIds(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "i\n\tifs\n"
+            "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+        source.addReader(&reader);
+
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
+        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
+           "ifs");
+        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
+           "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+    }
+
+    void testBasic(){
+        ReSource source;
+        ReStringReader reader(source);
+        source.addReader(&reader);
+        reader.addSource("<main>", "if i>1 then i=1+2*_x9 fi");
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        ReToken* token;
+        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
+        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
+        checkToken(lex.nextToken(), TOKEN_OPERATOR, OP_GT);
+        token = checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkEqu(1, token->asInteger());
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
+        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_THEN);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
+
+    }
+    void testPrio(){
+        ReSource source;
+        ReStringReader reader(source);
+        source.addReader(&reader);
+        reader.addSource("x", "");
+        enum { O_UNDEF, O_ASSIGN, O_PLUS, O_MINUS, O_TIMES, O_DIV
+             };
+        ReLexer lex(&source, KEYWORDS,
+                     "=\n+ -\n* /", "=",
+                 COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkT(lex.prioOfOp(O_ASSIGN) < lex.prioOfOp(O_PLUS));
+        checkEqu(lex.prioOfOp(O_PLUS), lex.prioOfOp(O_MINUS));
+        checkT(lex.prioOfOp(O_MINUS) < lex.prioOfOp(O_TIMES));
+        checkEqu(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV));
+    }
+
+    virtual void run(void) {
+        testPrio();
+        testBasic();
+        testIds();
+        testKeywords();
+        testComments();
+        testStrings();
+        testOperators();
+        testNumeric();
+        testSpace();
+        testRplToken();
+    }
+};
+void testReLexer() {
+    TestRplLexer test;
+    test.run();
+}
diff --git a/cunit/cuReMFParser.cpp b/cunit/cuReMFParser.cpp
new file mode 100644 (file)
index 0000000..04df740
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * rplmfparser_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 parser for the language "MF".
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+class TestReMFParser : public ReTest{
+private:
+    ReSource m_source;
+    ReASTree m_tree;
+    ReStringReader m_reader;
+    ReFileReader m_fileReader;
+    QByteArray m_currentSource;
+public:
+    TestReMFParser() :
+        ReTest("ReMFParser"),
+        m_source(),
+        m_tree(),
+        m_reader(m_source),
+        m_fileReader(m_source)
+    {
+        m_source.addReader(&m_reader);
+        doIt();
+    }
+protected:
+    void setSource(const char* content){
+        ReASItem::reset();
+        m_currentSource = content;
+        m_tree.clear();
+        m_source.clear();
+        m_reader.clear();
+        m_reader.addSource("<test>", content);
+        m_source.addReader(&m_reader);
+        m_source.addSourceUnit(m_reader.currentSourceUnit());
+    }
+    void setFileSource(const char* filename){
+        ReASItem::reset();
+        m_currentSource = ReStringUtil::read(filename);
+        m_tree.clear();
+        m_source.clear();
+        m_fileReader.clear();
+        m_fileReader.addSource(filename);
+        m_source.addReader(&m_fileReader);
+        m_source.addSourceUnit(m_fileReader.currentSourceUnit());
+    }
+
+private:
+    void checkAST(const char* fileExpected, int lineNo){
+        QByteArray fnExpected = "test";
+        fnExpected += QDir::separator().toLatin1();
+        fnExpected += "mfparser";
+        fnExpected += (char) QDir::separator().toLatin1();
+        fnExpected += fileExpected;
+        QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser");
+        m_tree.dump(fnCurrent, ReASTree::DMP_NO_GLOBALS, m_currentSource);
+        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
+                         __FILE__, lineNo);
+    }
+
+public:
+    void fileClassTest(){
+        setFileSource("test/rplmfparser/string1.mf");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("string1.txt", __LINE__);
+    }
+
+    void baseTest(){
+        setSource("2+3*4");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("baseTest.txt", __LINE__);
+    }
+
+    void varDefTest(){
+        setSource("const lazy Str s = 'Hi';\nconst List l;\nInt i = 3;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("varDefTest.txt", __LINE__);
+    }
+
+    void ifTest(){
+        setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi");
+        // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("ifTest1.txt", __LINE__);
+        setSource("Str x;\nif 7 < 6\nthen x = '123';\nfi");
+        parser.parse();
+        checkAST("ifTest2.txt", __LINE__);
+    }
+    void whileTest(){
+        setSource("Int a = 20;\nwhile 3 < 5 do\n a = 7\nod");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("whileTest.txt", __LINE__);
+    }
+
+    void repeatTest(){
+        setSource("Int a;\nrepeat\na++;\nuntil a != 2 * 3;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("repeatTest.txt", __LINE__);
+    }
+    void forCTest(){
+        setSource("Int a;\nfor b from 10 to 1 step -2 do\na += 1;\nod");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("forC1.txt", __LINE__);
+        setSource("Int a; for to 10 do a += 1 od");
+        parser.parse();
+        checkAST("forC2.txt", __LINE__);
+    }
+    void opTest(){
+        checkEqu(25, ReMFParser::O_QUESTION);
+        checkEqu(37, ReMFParser::O_RSHIFT2);
+        checkEqu(41, ReMFParser::O_DEC);
+        checkEqu(48, ReMFParser::O_RBRACE);
+        setSource("Int a = 1;\nInt b = 100;\n--a;\nb++;\na--*++b**(8-3);\na=b=(a+(b-2)*3)");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("opTest1.txt", __LINE__);
+    }
+    void forItTest(){
+        setSource("Map a;\nfor x in a do\na += 1;\nod");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("forIt1.txt", __LINE__);
+    }
+    void listTest(){
+        ReMFParser parser(m_source, m_tree);
+        setSource("List b = [];");
+        parser.parse();
+        checkAST("list1.txt", __LINE__);
+        setSource("List a = [2+3, 3.14, 7, 'hi', a]; List b = [];");
+        parser.parse();
+        checkAST("list2.txt", __LINE__);
+    }
+    void mapTest(){
+        setSource("Map a = {};");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("map1.txt", __LINE__);
+        setSource("Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};\nMap b = {};");
+        parser.parse();
+        checkAST("map2.txt", __LINE__);
+    }
+    void methodCallTest(){
+        //setSource("max(4,3.14);");
+        setSource("rand();\nsin(a);\nmax(1+2*3,4**(5-4));");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("methc1.txt", __LINE__);
+    }
+    void fieldTest(){
+        setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("field1.txt", __LINE__);
+    }
+
+    void methodTest(){
+        setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("meth1.txt", __LINE__);
+        setSource("func Int fac(const Int n):\n"
+                  "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n"
+                  "rc endf");
+        parser.parse();
+        checkAST("meth2.txt", __LINE__);
+        setSource("func Int max(Int a, Int b):\n Int rc = a;\n"
+                  "if a < b then rc = b; fi\nrc\n"
+                  "endf\n"
+                  "func Int max(const Int a, Int b, Int c):\n"
+                  "max(a, max(b, c))\n"
+                  "endf");
+        parser.parse();
+        checkAST("meth3.txt", __LINE__);
+        setSource("func Int max(const Int a, Int b, Int c):\n"
+                  "func Int max(Int a, Int b):\n Int rc = a;\n"
+                  "if a < b then rc = b; fi\nrc\n"
+                  "endf\n"
+                  "max(a, max(b, c))\n"
+                  "endf");
+        parser.parse();
+        checkAST("meth4.txt", __LINE__);
+    }
+    void mainTest(){
+        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("main1.txt", __LINE__);
+    }
+
+    virtual void run(void) {
+        mainTest();
+        varDefTest();
+        repeatTest();
+        baseTest();
+        whileTest();
+        methodTest();
+        fieldTest();
+        methodCallTest();
+        mapTest();
+        forItTest();
+        forCTest();
+        listTest();
+        opTest();
+        fileClassTest();
+    }
+};
+void testReMFParser() {
+    TestReMFParser test;
+}
+
+
diff --git a/cunit/cuReMatrix.cpp b/cunit/cuReMatrix.cpp
new file mode 100644 (file)
index 0000000..55b568e
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * rplmatrix_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 matrices.
+ */
+
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+
+class TestRplMatrix : public ReTest{
+public:
+    TestRplMatrix() : ReTest("RplMatrix") { doIt(); }
+
+public:
+    void fillMatrix(RplMatrix& mx, MatVal offset = 0){
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                mx.set(row, col, 100.0*row + col + offset);
+            }
+        }
+    }
+    void checkMatrix(const RplMatrix& mx, MatVal offset = 0){
+        int count = 0;
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                checkEqu(100.0*row + col + offset, mx.get(row, col));
+                count++;
+            }
+        }
+        checkEqu(mx.getCols()*mx.getRows(), count);
+    }
+    void fillConst(RplMatrix& mx, MatVal value){
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                mx.set(row, col, value);
+            }
+        }
+    }
+    void checkConst(const RplMatrix& mx, MatVal value){
+        int count = 0;
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                checkEqu(value, mx.get(row, col));
+                count++;
+            }
+        }
+        checkEqu(mx.getCols()*mx.getRows(), count);
+    }
+
+    void testBasic() {
+        Tuple2 tuple(-2.0, 0.5);
+        checkEqu(-2.0, tuple.m_value1);
+        checkEqu(0.5, tuple.m_value2);
+        RplMatrix mat("mx");
+        try{
+            throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (RplMatrixException exc){
+            checkEqu("mx: String: Hi and int -333", exc.getMessage());
+        }
+        RplMatrix mat2;
+        try{
+            throw RplMatrixException(mat2, "String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (RplMatrixException exc){
+            checkEqu("String: Hi and int -333", exc.getMessage());
+        }
+        checkEqu("mx", mat.getName());
+        checkEqu("", mat2.getName());
+
+        RplMatrix m2x3(2, 3, "m2x3");
+        checkEqu("m2x3", m2x3.getName());
+        checkEqu(2, m2x3.getRows());
+        checkEqu(3, m2x3.getCols());
+        fillMatrix(m2x3);
+        checkMatrix(m2x3);
+
+        RplMatrix mxCopy(m2x3);
+        checkEqu("m2x3-copy", mxCopy.getName());
+        checkEqu(2, mxCopy.getRows());
+        checkEqu(3, mxCopy.getCols());
+        checkMatrix(mxCopy);
+
+        RplMatrix mxCopy2("mxCopy2");
+        mxCopy2 = m2x3;
+        checkEqu("mxCopy2", mxCopy2.getName());
+        checkEqu(2, mxCopy2.getRows());
+        checkEqu(3, mxCopy2.getCols());
+        checkMatrix(mxCopy2);
+    }
+    void testAddOperators(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(3, 2, "m2");
+        fillMatrix(m2, 42);
+        checkMatrix(m2, 42);
+        RplMatrix m3(3, 2, "m3");
+        fillMatrix(m3, -42);
+        checkMatrix(m3, -42);
+
+        m1 += 42;
+        checkMatrix(m1, 42);
+
+        checkT(m1 == m2);
+        checkF(m1 == m3);
+
+        m1 -= 42;
+        checkMatrix(m1);
+        m1 -= m1;
+        checkConst(m1, 0);
+
+        fillMatrix(m1);
+        m1 -= m3;
+        checkConst(m1, 42);
+        m1 += m2;
+        checkMatrix(m1, 42*2);
+    }
+    void testCompareOperators(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(3, 2, "m2");
+        fillMatrix(m2);
+
+        checkT(m1 == m2);
+        checkF(m1 != m2);
+        // modify each element, comparism must return false:
+        int row, col;
+        for (row = 0; row < m2.getRows(); row++)
+            for (col = 0; col < m2.getCols(); col++){
+                fillMatrix(m2);
+                m2.set(row, col, -1);
+                checkF(m1 == m2);
+                checkT(m1 != m2);
+            }
+
+        fillConst(m1, 42);
+        checkT(m1 == 42);
+        checkF(m1 == 43);
+        checkT(m1 != 43);
+        for (row = 0; row < m1.getRows(); row++)
+            for (col = 0; col < m1.getCols(); col++){
+                fillMatrix(m1, 42);
+                m1.set(row, col, -1);
+                checkF(m1 == 42);
+                checkT(m1 != 42);
+            }
+    }
+
+    void testCheckDefinition(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(3, 2, "m2");
+        fillMatrix(m2);
+
+        m1.checkDefinition(1, 1);
+        m1.checkDefinition(1000, 1000);
+        m1.checkDefinition(0, 0);
+        try {
+            m1.checkDefinition(-1, 1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: row number negative: -1", exc.getMessage());
+        }
+        try {
+            m1.checkDefinition(1, -1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: column number negative: -1", exc.getMessage());
+        }
+
+    }
+    void testCheck(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+
+        m1.check(0, 0);
+        m1.check(3-1, 2-1);
+        try {
+            m1.check(-1, 1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid row: -1 not in [0,3[", exc.getMessage());
+        }
+        try {
+            m1.check(3, 1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid row: 3 not in [0,3[", exc.getMessage());
+        }
+        try {
+            m1.check(1, -1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid column: -1 not in [0,2[", exc.getMessage());
+        }
+        try {
+            m1.check(1, 2);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid column: 2 not in [0,2[", exc.getMessage());
+        }
+    }
+    void testCheckSameDimension(){
+        RplMatrix m1(3, 2, "m1");
+        RplMatrix m2(3, 2, "m2");
+
+        m1.checkSameDimension(m2);
+
+        m2.resize(2, 2);
+        try {
+            m1.checkSameDimension(m2);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: m2 has a different row count: 3 / 2", exc.getMessage());
+        }
+        m2.resize(3, 3);
+        try {
+            m1.checkSameDimension(m2);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: m2 has a different column count: 2 / 3", exc.getMessage());
+        }
+    }
+    void testResize(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(2, 4, "m2");
+        fillConst(m2, 0);
+        checkConst(m2, 0);
+
+        m1.resize(2, 4);
+        checkEqu(2, m1.getRows());
+        checkEqu(4, m1.getCols());
+        checkT(m1 == m2);
+    }
+
+    void testMinMax(){
+        RplMatrix m1(4, 5, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        m1.set(0, 0, -98);
+        m1.set(3, 4, 9999);
+        Tuple2 miniMax = m1.minMax();
+        checkEqu(-98.0, miniMax.m_value1);
+        checkEqu(9999.0, miniMax.m_value2);
+
+        fillMatrix(m1);
+        checkMatrix(m1);
+        m1.set(1, 1, 7777);
+        m1.set(3, 4, -987);
+        miniMax = m1.minMax();
+        checkEqu(-987.0, miniMax.m_value1);
+        checkEqu(7777.0, miniMax.m_value2);
+    }
+
+    void testTranspose()
+    {
+        RplMatrix m1(1, 5, "m1");
+        fillMatrix(m1);
+        RplMatrix m2(m1.transpose());
+
+        checkEqu(5, m2.getRows());
+        checkEqu(1, m2.getCols());
+
+        int row, col;
+        col = 0;
+        for (row = 0; row < 5; row++){
+            checkEqu(qreal(col*100+row), m2.get(row, 0));
+        }
+
+        m1.resize(35, 73);
+        fillMatrix(m1);
+        m2 = m1.transpose();
+
+        checkEqu(73, m2.getRows());
+        checkEqu(35, m2.getCols());
+
+        int count = 0;
+        for (row = 0; row < m2.getRows(); row++){
+            for (col = 0; col < m2.getCols(); col++){
+                checkEqu(qreal(col*100+row), m2.get(row, col));
+                count++;
+            }
+        }
+        checkEqu(73*35, count);
+    }
+    void testToString(){
+        RplMatrix m1(1, 1, "m1");
+        m1.set(0, 0, 2.34);
+        checkEqu("[2.340000,\n]", m1.toString().constData());
+        checkEqu("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
+
+        m1.resize(2, 1);
+        m1.set(0, 0, 2.34);
+        m1.set(1, 0, 55.5);
+
+        checkEqu("[2.340000,\n55.500000,\n]", m1.toString().constData());
+        checkEqu("jonny[2.34000 |55.50000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
+        log("");
+    }
+    void testReadCsv(){
+        QByteArray fn = getTempFile("rplmatrixtest.csv");
+        const char* content;
+        RplMatrix m1(1,1,"m1");
+
+        fillMatrix(m1);
+        content = ",Port0,Port1,Port2\n"
+                "element1,5,  -3E-99  , 0.5\n"
+                "element2,7,-22.3,44\n"
+                "\n"
+                "2 Elements, 3, Ports";
+        ReStringUtil::write(fn, content);
+        m1.readFromCvs(fn, 256);
+        checkEqu(2, m1.getRows());
+        checkEqu(3, m1.getCols());
+
+        checkEqu(5.0, m1.get(0, 0));
+        checkEqu(-3.0E-99, m1.get(0, 1));
+        checkEqu(0.5, m1.get(0, 2));
+
+        checkEqu(7.0, m1.get(1, 0));
+        checkEqu(-22.3, m1.get(1, 1));
+        checkEqu(44.0, m1.get(1, 2));
+
+        fillMatrix(m1);
+        content = "Port0,Port1,Port2\n"
+                "5,  -3E-99  , 0.5\n";
+        ReStringUtil::write(fn, content);
+        m1.readFromCvs(fn, 256);
+        checkEqu(1, m1.getRows());
+        checkEqu(3, m1.getCols());
+        checkEqu(5.0, m1.get(0, 0));
+        checkEqu(-3.0E-99, m1.get(0, 1));
+        checkEqu(0.5, m1.get(0, 2));
+
+
+/*
+    void readFromCvs(const char* filename, int maxLineLength = 1024*1024);
+    void readFromXml(const char* filename, const char* tagCol,
+            const char* tagRow, const char* tagTable,
+            int maxLineLength = 1024*1024);
+*/
+    }
+    virtual void run(void) {
+        testBasic();
+        testAddOperators();
+        testCompareOperators();
+        testCheckDefinition();
+        testCheck();
+        testCheckSameDimension();
+        testResize();
+        testMinMax();
+        testTranspose();
+        testToString();
+        testReadCsv();
+    }
+};
+void testRplMatrix() {
+    TestRplMatrix test;
+}
diff --git a/cunit/cuReQStringUtil.cpp b/cunit/cuReQStringUtil.cpp
new file mode 100644 (file)
index 0000000..c04145d
--- /dev/null
@@ -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/cuReSource.cpp b/cunit/cuReSource.cpp
new file mode 100644 (file)
index 0000000..05b1b32
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * rplsource_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 input media reader.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+class TestReSource : public ReTest{
+public:
+    TestReSource() : ReTest("TestReSource") { doIt(); }
+
+private:
+    QByteArray m_content1_1;
+    QByteArray m_content1_2;
+    QByteArray m_content2;
+    ReSource m_source;
+
+protected:
+    void init(){
+        m_content1_1 = "# test\nimport source2\n";
+        m_content1_2 = "a=1;\nveeeeeeeeery looooooooooooooong\n";
+        m_content2 = "x=2";
+    }
+
+    void testReStringSourceUnit(){
+        ReStringReader reader(m_source);
+        QByteArray content("a=1;\nveeeeeeeeery looooooooooooooong\n");
+        ReStringSourceUnit unit("test", content, &reader);
+        unit.setLineNo(144);
+        checkEqu(144, unit.lineNo());
+        checkEqu("test", unit.name());
+    }
+    void checkOne(int maxSize, ReReader& reader){
+        QByteArray total;
+        QByteArray buffer;
+        int lineNo = 0;
+        bool hasMore;
+        checkF(reader.openSourceUnit("unknownSource"));
+        checkT(reader.openSourceUnit("source1"));
+        while(reader.nextLine(maxSize, buffer, hasMore)){
+            lineNo++;
+            total += buffer;
+            buffer.clear();
+            while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
+                total += buffer;
+                buffer.clear();
+            }
+            bool isImport = total.endsWith("source2\n");
+            if (isImport){
+                reader.openSourceUnit("source2");
+                checkEqu("source2", reader.currentSourceUnit()->name());
+                while(reader.nextLine(maxSize, buffer, hasMore)){
+                    lineNo++;
+                    while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
+                        total += buffer;
+                        buffer.clear();
+                    }
+                }
+                checkEqu("source1", reader.currentSourceUnit()->name());
+            }
+        }
+        checkEqu(5, lineNo);
+        checkEqu(m_content1_1 + m_content2 + m_content1_2, total);
+
+    }
+
+    void testReStringReader(){
+        ReStringReader reader(m_source);
+        reader.addSource("source1", m_content1_1 + m_content1_2);
+        reader.addSource("source2", m_content2);
+        ReSourceUnit* unit = reader.openSourceUnit("source1");
+        checkNN(unit);
+        checkEqu("source1", unit->name());
+        checkEqu(0, unit->lineNo());
+        checkOne(6, reader);
+        checkOne(100, reader);
+        reader.replaceSource("source2", "content2");
+
+        unit = reader.openSourceUnit("source2");
+        QByteArray buffer;
+        bool hasMore;
+        checkT(reader.nextLine(50, buffer, hasMore));
+        checkEqu("content2", buffer);
+        checkF(hasMore);
+    }
+
+public:
+    void run(void) {
+        init();
+        testReStringSourceUnit();
+        testReStringReader();
+    }
+};
+void testReSource() {
+    TestReSource test;
+}
+
+
+
diff --git a/cunit/cuReStringUtil.cpp b/cunit/cuReStringUtil.cpp
new file mode 100644 (file)
index 0000000..e107a24
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * rplstring_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 QByteArray tools.
+ */
+#include "base/rebase.hpp"
+/**
+ * @brief Unit test for <code>ReStringUtil</code>.
+ */
+class TestReStringUtil : public ReTest {
+public:
+    TestReStringUtil() : ReTest("ReStringUtil") { doIt(); }
+
+public:
+    void testCountChar(){
+        checkEqu(1, ReStringUtil::countChar("x", 'x'));
+        checkEqu(0, ReStringUtil::countChar("X", 'x'));
+        checkEqu(2, ReStringUtil::countChar("xbxxbxx", 'b'));
+    }
+
+    void testCount() {
+        checkEqu(0, ReStringUtil::count("abc", " "));
+        checkEqu(1, ReStringUtil::count("abc", "b"));
+        checkEqu(2, ReStringUtil::count("axx", "x"));
+
+        checkEqu(0, ReStringUtil::count("abbc", "bbb"));
+        checkEqu(1, ReStringUtil::count("\n\n", "\n\n"));
+        checkEqu(2, ReStringUtil::count("  a  ", "  "));
+    }
+
+    void testCutString() {
+        QByteArray source("123");
+        QByteArray buffer;
+        checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 4, buffer));
+        checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 3, buffer));
+        checkEqu(QByteArray("12..."), ReStringUtil::cutString(source, 2, buffer));
+        checkEqu(QByteArray("12"), ReStringUtil::cutString(source, 2, buffer, ""));
+    }
+
+    void testHexDump() {
+        QByteArray data("abc123\nxyz");
+        checkEqu(QByteArray("61 62 63 31  abc1\n"
+                          "32 33 0a 78  23.x\n"
+                          "79 7a        yz\n"),
+               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 4));
+        checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a  abc123.xyz"),
+               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 10));
+        checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a        abc123.xyz"),
+               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 12));
+    }
+
+    void testReadWrite() {
+        QByteArray fn = getTempFile("test.dat");
+        const char* content = "Hello world\nLine2\n";
+        checkT(ReStringUtil::write(fn, content));
+        checkEqu(content, ReStringUtil::read(fn, false));
+        checkEqu(content, ReStringUtil::read(fn, true) + "\n");
+    }
+
+    void testToArray() {
+        QList<QByteArray> array = ReStringUtil::toArray("1 abc 3", " ");
+        checkEqu(3, array.size());
+        checkEqu("1", array.at(0));
+        checkEqu("abc", array.at(1));
+        checkEqu("3", array.at(2));
+    }
+
+    void testToNumber() {
+        checkEqu("3", ReStringUtil::toNumber(3));
+        checkEqu("-33", ReStringUtil::toNumber(-33));
+        checkEqu("003", ReStringUtil::toNumber(3, "%03d"));
+    }
+
+    void testLengthOfNumber(){
+        checkEqu(3, ReStringUtil::lengthOfNumber("0.3xxx"));
+        checkEqu(5, ReStringUtil::lengthOfNumber(" \t0.3xxx"));
+        checkEqu(3, ReStringUtil::lengthOfNumber("-.3xxx"));
+        checkEqu(2, ReStringUtil::lengthOfNumber(".3exxx"));
+        checkEqu(2, ReStringUtil::lengthOfNumber(".3e+xxx"));
+        checkEqu(16, ReStringUtil::lengthOfNumber("1234567.9012E+77"));
+        checkEqu(17, ReStringUtil::lengthOfNumber("-1234567.9012E+77 "));
+        checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ", true));
+        checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 x", true));
+        checkEqu(20, ReStringUtil::lengthOfNumber("  -1234567.9012E+77 x", true));
+    }
+
+    void checkCsv(const char* content, char expected){
+        QByteArray fn = getTempFile("testrplstring.csv");
+        ReStringUtil::write(fn, content);
+        FILE* fp = fopen(fn, "r");
+        checkNN(fp);
+        char buffer[256];
+        checkEqu(expected, ReStringUtil::findCsvSeparator(fp, buffer, sizeof buffer));
+        fclose(fp);
+    }
+
+    void testFindCsvSeparator(){
+        const char* content = ",,,\t;;;||||";
+        checkCsv(content, '\t');
+
+        content = "col1,col2\n1.5,3,5\n";
+        checkCsv(content, ',');
+
+        content = "col1;col2\n1,50;3.5\n"
+                 "7;8\n10;12\n13;14";
+        checkCsv(content, ';');
+
+        content = "0.3 7.8 8.9\n7.8 9.4 8.3";
+        checkCsv(content, ' ');
+
+        content = "0.3|7.8|8.9\n7.8|         9.4|8.3";
+        checkCsv(content, '|');
+
+        content = "0,3;7.8;8.9";
+        checkCsv(content, ';');
+    }
+    void testLengthOfUInt64(){
+        quint64 value = -3;
+        checkEqu(1, ReStringUtil::lengthOfUInt64("0", 10, &value));
+        checkEqu((int64_t) 0LL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432", 10, &value));
+        checkEqu((int64_t) 432LL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432 x", 10, &value));
+        checkEqu((int64_t) 432LL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432fabc x", 10, &value));
+        checkEqu((int64_t) 432LL, value);
+        checkEqu(16, ReStringUtil::lengthOfUInt64("1234567890123567", 10, &value));
+        checkEqu((int64_t) 1234567890123567LL, value);
+        checkEqu(10, ReStringUtil::lengthOfUInt64("1234abcdef", 16, &value));
+        checkEqu((int64_t) 0x1234abcdefLL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432", 8, &value));
+        checkEqu((int64_t) 0432LL, value);
+        checkEqu(6, ReStringUtil::lengthOfUInt64("765432 ", 8, &value));
+        checkEqu((int64_t) 0765432LL, value);
+
+        checkEqu(0, ReStringUtil::lengthOfUInt64(" ", 8, &value));
+        checkEqu(0, ReStringUtil::lengthOfUInt64("", 8, &value));
+    }
+    void testLengthOfReal(){
+        qreal value;
+        checkEqu(1, ReStringUtil::lengthOfReal("0", &value));
+        checkEqu(0.0, value);
+        checkEqu(1, ReStringUtil::lengthOfReal("0%", &value));
+        checkEqu(0.0, value);
+        checkEqu(4, ReStringUtil::lengthOfReal("0.25", &value));
+        checkEqu(0.25, value);
+        checkEqu(3, ReStringUtil::lengthOfReal(".25", &value));
+        checkEqu(0.25, value);
+        checkEqu(17, ReStringUtil::lengthOfReal("12345678901234567", &value));
+        checkEqu(12345678901234567.0, value);
+        checkEqu(2, ReStringUtil::lengthOfReal(".5", &value));
+        checkEqu(0.5, value);
+        checkEqu(5, ReStringUtil::lengthOfReal("2.5e2x", &value));
+        checkEqu(250.0, value);
+        checkEqu(6, ReStringUtil::lengthOfReal("2.5e+2", &value));
+        checkEqu(250.0, value);
+        checkEqu(7, ReStringUtil::lengthOfReal("2.5E-33", &value));
+        checkEqu(2.5e-33, value);
+
+        checkEqu(3, ReStringUtil::lengthOfReal("2.5E", &value));
+        checkEqu(2.5, value);
+        checkEqu(3, ReStringUtil::lengthOfReal("2.5E+", &value));
+        checkEqu(2.5, value);
+        checkEqu(3, ReStringUtil::lengthOfReal("2.5E-a", &value));
+        checkEqu(2.5, value);
+    }
+
+    virtual void run() {
+        testLengthOfReal();
+        testLengthOfUInt64();
+        testCountChar();
+        testCount();
+        testCutString();
+        testToNumber();
+        testToArray();
+        testHexDump();
+        testReadWrite();
+        testLengthOfNumber();
+        testFindCsvSeparator();
+    }
+};
+
+void testReStringUtil() {
+    TestReStringUtil test;
+}
+
+
+
diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp
new file mode 100644 (file)
index 0000000..90cc05c
--- /dev/null
@@ -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/cuReVM.cpp b/cunit/cuReVM.cpp
new file mode 100644 (file)
index 0000000..9befa8c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * rplvm_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
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+class TestReVM : public ReTest{
+private:
+    ReSource m_source;
+    ReASTree m_tree;
+    ReStringReader m_reader;
+    const char* m_currentSource;
+public:
+    TestReVM() :
+        ReTest("ReVM"),
+        m_source(),
+        m_tree(),
+        m_reader(m_source)
+    {
+        m_source.addReader(&m_reader);
+        doIt();
+    }
+protected:
+    void setSource(const char* content){
+        ReASItem::reset();
+        m_currentSource = content;
+        m_tree.clear();
+        m_source.clear();
+        m_reader.clear();
+        m_reader.addSource("<test>", content);
+        m_source.addReader(&m_reader);
+        m_source.addSourceUnit(m_reader.currentSourceUnit());
+    }
+
+private:
+    void checkAST(const char* fileExpected, int lineNo){
+        QByteArray fnExpected = "test";
+        fnExpected += QDir::separator().toLatin1();
+        fnExpected += "ReVM";
+        fnExpected += (char) QDir::separator().toLatin1();
+        fnExpected += fileExpected;
+        QByteArray fnCurrent = getTempFile(fileExpected, "ReVM");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        ReVirtualMachine vm(m_tree, m_source);
+        vm.setFlag(ReVirtualMachine::VF_TRACE_STATEMENTS);
+        ReFileWriter writer(fnCurrent);
+        vm.setTraceWriter(&writer);
+        writer.write(m_currentSource);
+        vm.executeModule("<test>");
+        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
+                         __FILE__, lineNo);
+    }
+public:
+    void baseTest(){
+        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
+        checkAST("baseTest.txt", __LINE__);
+    }
+    virtual void run(void) {
+        baseTest();
+    }
+};
+void testReVM() {
+    TestReVM test;
+}
+
diff --git a/cunit/cuReWriter.cpp b/cunit/cuReWriter.cpp
new file mode 100644 (file)
index 0000000..67e2389
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * rplwriter_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 output media writers.
+ */
+
+#include "base/rebase.hpp"
+/**
+ * @brief Unit test for <code>ReStringUtil</code>.
+ */
+class TestReWriter : public ReTest {
+public:
+    TestReWriter() : ReTest("ReWriter") { doIt(); }
+
+private:
+    void testFileWriter(){
+        QByteArray fn = getTempFile("rplwriter.txt");
+        ReFileWriter writer(fn);
+        writer.writeLine("abc");
+        writer.formatLine("%04d", 42);
+        writer.writeIndented(3, "123");
+        writer.indent(2);
+        writer.write("pi");
+        writer.format("%3c%.2f", ':', 3.1415);
+        writer.writeLine();
+        writer.close();
+        QByteArray current = ReStringUtil::read(fn, false);
+        checkEqu("abc\n0042\n\t\t\t123\n\t\tpi  :3.14\n", current);
+    }
+
+public:
+    virtual void run(void) {
+        testFileWriter();
+    }
+};
+void testReWriter() {
+    TestReWriter test;
+}
+
+
+
diff --git a/cunit/main.cpp b/cunit/main.cpp
deleted file mode 100644 (file)
index 0922b20..0000000
+++ /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 <QCoreApplication>
-
-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/rplastree_test.cpp b/cunit/rplastree_test.cpp
deleted file mode 100644 (file)
index 0a98a23..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * rplastree_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 abstract syntax tree.
- */
-
-
-#include "base/rebase.hpp"
-#include "expr/reexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestReASTree : public ReTest{
-private:
-    ReSource m_source;
-    ReStringReader m_reader;
-    ReStringSourceUnit m_unit;
-    ReASTree m_tree;
-public:
-    TestReASTree() :
-        ReTest("ReASTree"),
-        m_source(),
-        m_reader(m_source),
-        m_unit("<main>", "", &m_reader),
-        m_tree()
-    {}
-public:
-    void testReASException() {
-        try{
-            m_reader.addSource("<main>", "12");
-            m_source.addReader(&m_reader);
-            m_source.addSourceUnit(m_reader.currentSourceUnit());
-            const ReSourcePosition* pos = m_source.newPosition(2);
-            throw ReASException(pos, "simple string: %s", "Hi");
-            checkF(true);
-        } catch (ReASException exc){
-            checkEqu("<main>:0:2: simple string: Hi", exc.getMessage().constData());
-        }
-    }
-    void testReASVariant(){
-        ReASVariant val1;
-        val1.setFloat(2.5E-2);
-        checkEqu(2.5E-2, val1.asFloat());
-        ReASVariant val2(val1);
-        checkEqu(2.5E-2, val2.asFloat());
-
-        val1.setInt(4321);
-        checkEqu(4321, val1.asInt());
-        val2 = val1;
-        checkEqu(4321, val2.asInt());
-
-        val1.setBool(false);
-        checkF(val1.asBool());
-        val2 = val1;
-        checkF(val2.asBool());
-
-        val1.setBool(true);
-        checkT(val1.asBool());
-        val2 = val1;
-        checkT(val2.asBool());
-
-        val1.setString("High noon!");
-        checkEqu("High noon!", *val1.asString());
-        val2 = val1;
-        val1.setString("Bye");
-        checkEqu("High noon!", *val2.asString());
-        ReASVariant val3(val1);
-        checkEqu("Bye", *val3.asString());
-    }
-    void testReASConstant(){
-        ReASConstant constant;
-        //constant.value().setString("Jonny");
-        ReASVariant value;
-        //constant.calc(value);
-        //checkEqu("Jonny", *value.asString());
-    }
-    void testReASNamedValue(){
-        ReASNamedValue value(NULL, m_tree.symbolSpaces()[0], "gugo",
-                ReASNamedValue::A_GLOBAL);
-        checkEqu("gugo", value.name());
-    }
-    virtual void doIt() {
-        testReASNamedValue();
-        testReASConstant();
-        testReASException();
-        testReASVariant();
-    }
-};
-void testReASTree() {
-    TestReASTree test;
-    test.run();
-}
-
-
-
-
-
-
diff --git a/cunit/rplbench.cpp b/cunit/rplbench.cpp
deleted file mode 100644 (file)
index 31f0e8a..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * rplbench.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 abstract syntax tree.
- */
-
-
-#include "base/rebase.hpp"
-#include "expr/reexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplBenchmark : public ReTest{
-private:
-    const char* m_filename;
-    ReSource m_source;
-    ReFileReader m_reader;
-    ReASTree m_tree;
-public:
-    TestRplBenchmark() :
-        ReTest("RplBenchmark"),
-        m_filename("/home/ws/qt/rplqt/bench/mfbench.mf"),
-        m_source(),
-        m_reader(m_source),
-        m_tree()
-    {
-        m_source.addReader(&m_reader);
-        m_reader.addSource(m_filename);
-    }
-public:
-    void benchmark() {
-        time_t start = time(NULL);
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        time_t end = time(NULL);
-        printf("compilation: %d sec\n", int(end - start));
-    }
-    virtual void doIt() {
-        try{
-            ReFileSourceUnit* unit = dynamic_cast<ReFileSourceUnit*>
-                    (m_reader.currentSourceUnit());
-            if (unit != NULL && ! unit->isOpen())
-                throw ReException("file not found: %s", m_filename);
-            benchmark();
-        } catch(ReException ex){
-            printf("%s\n", ex.getMessage().constData());
-        }
-    }
-};
-void testRplBenchmark() {
-    TestRplBenchmark test;
-    test.run();
-}
-
-
-
diff --git a/cunit/rplbytestorage_test.cpp b/cunit/rplbytestorage_test.cpp
deleted file mode 100644 (file)
index 0f40bc6..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * rplbytestorage_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 byte and C string storage.
- */
-
-#include "../base/rebase.hpp"
-#include "../base/ReTest.hpp"
-
-class TestRplByteStorage : public ReTest{
-public:
-    TestRplByteStorage() :
-        ReTest("RplByteStorage")
-    {}
-private:
-    void testChars(){
-        ReByteStorage store(100);
-        char* s1 = store.allocateChars(4);
-        memcpy((void*) s1, "123", 4);
-        const char* s2 = store.allocateChars("abc");
-        const char* s3 = store.allocateChars("defghij", 3);
-        checkEqu(s1, "123");
-        checkEqu(s2, "abc");
-        checkEqu(s3, "def");
-        const char* ptr = s1 + 4;
-        checkT(ptr == s2);
-        ptr += 4;
-        checkT(ptr == s3);
-    }
-
-    void testBytes(){
-        ReByteStorage store(100);
-        uint8_t* s1 = store.allocateBytes(4);
-        memcpy((void*) s1, "1234", 4);
-        uint8_t* s2 = store.allocateBytes((void*) "abcd", 4);
-        uint8_t* s3 = store.allocateBytes((void*) "efghij", 4);
-        uint8_t* s4 = store.allocateZeros(4);
-
-        checkEqu("1234abcdefgh", (const char*) s1);
-        uint8_t* ptr = s1 + 4;
-        checkT(ptr == s2);
-        ptr += 4;
-        checkT(ptr == s3);
-        ptr += 4;
-        checkT(ptr == s4);
-        for (int ii = 0; ii < 4; ii++)
-            checkEqu(0, (int) s4[ii]);
-    }
-    void testBufferChange(){
-        ReByteStorage store(10);
-        char buffer[2];
-        buffer[1] = '\0';
-        for (int ii = 0; ii < 10000; ii++){
-            buffer[1] = 'A' + ii % 26;
-            store.allocateBytes(buffer, 1);
-        }
-        int a = 1;
-    }
-
-public:
-    virtual void doIt() {
-        testBufferChange();
-        testChars();
-        testBytes();
-    }
-};
-void testRplByteStorage() {
-    TestRplByteStorage test;
-    test.run();
-}
-
-
diff --git a/cunit/rplcharptrmap_test.cpp b/cunit/rplcharptrmap_test.cpp
deleted file mode 100644 (file)
index 0643b9e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * rplcharptrmap_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
- */
-
-#include "base/rebase.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestReCharPtrMap : public ReTest{
-public:
-    TestReCharPtrMap() :
-        ReTest("ReCharPtrMap")
-    {
-    }
-protected:
-    void testBasic(){
-        ReCharPtrMap<const char*> map;
-        map["x"] = "x1";
-        checkT(map.contains("x"));
-        checkF(map.contains("y"));
-        checkEqu("x1", map["x"]);
-    }
-
-    virtual void doIt(void) {
-        testBasic();
-    }
-};
-void testReCharPtrMap() {
-    TestReCharPtrMap test;
-    test.run();
-}
diff --git a/cunit/rplexception_test.cpp b/cunit/rplexception_test.cpp
deleted file mode 100644 (file)
index f219850..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * rplexception_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
- */
-#include "base/rebase.hpp"
-#include "rplcore/rpltest.hpp"
-/** @file
- * @brief Unit test of the basic exceptions.
- */
-
-class TestRplException : public ReTest{
-public:
-    TestRplException() : ReTest("RplException") {}
-
-public:
-    void testBasic() {
-        try{
-            throw ReException("simple");
-            checkF(true);
-        } catch (ReException exc){
-            checkEqu("simple", exc.getMessage().constData());
-        }
-        try{
-            throw ReException("String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (ReException exc){
-            checkEqu("String: Hi and int -333", exc.getMessage().constData());
-        }
-        try{
-            throw ReException(LOG_INFO, 1234, &m_memoryLogger,
-                    "String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (ReException exc){
-            checkT(logContains("^ .*\\(1234\\): String: Hi and int -333"));
-        }
-        log("ok");
-    }
-    virtual void doIt() {
-        testBasic();
-    }
-};
-void testRplException() {
-    TestRplException test;
-    test.run();
-}
-
-
-
diff --git a/cunit/rpllexer_test.cpp b/cunit/rpllexer_test.cpp
deleted file mode 100644 (file)
index 72f133e..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * rpllexer_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 syntax symbol extractor.
- */
-
-#include "base/rebase.hpp"
-#include "expr/reexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplLexer : public ReTest, public ReToken{
-public:
-    TestRplLexer() :
-        ReTest("ReLexer"),
-        ReToken(TOKEN_ID)
-    {}
-
-public:
-    void testRplToken(){
-        // test constructor values:
-        checkEqu(TOKEN_ID, tokenType());
-        checkEqu(0, m_value.m_id);
-        checkT(m_string.isEmpty());
-        checkT(m_printableString.isEmpty());
-
-        m_value.m_id = 7422;
-        checkEqu(7422, ReToken::id());
-        m_string = "Wow!";
-        checkEqu("Wow!", ReToken::toString());
-        m_printableString = "GooGoo";
-        checkEqu("GooGoo", rawString());
-        m_tokenType = TOKEN_NUMBER;
-        checkEqu(TOKEN_NUMBER, tokenType());
-
-        clear();
-        checkEqu(TOKEN_UNDEF, tokenType());
-        checkEqu(0, m_value.m_id);
-        checkT(m_string.isEmpty());
-        checkT(m_printableString.isEmpty());
-
-        m_value.m_integer = 773322;
-        checkEqu(773322, asInteger());
-        m_value.m_real = 0.25;
-        checkEqu(0.25, asReal());
-    }
-
-    ReToken* checkToken(ReToken* token, RplTokenType type, int id = 0,
-                    const char* string = NULL){
-        checkEqu(type, token->tokenType());
-        if (id != 0)
-            checkEqu(id, token->id());
-        if (string != NULL)
-            checkEqu(string, token->toString());
-        return token;
-    }
-    enum { KEY_UNDEF, KEY_IF, KEY_THEN, KEY_ELSE, KEY_FI
-         };
-#   define KEYWORDS "if then else fi"
-    enum { OP_UNDEF, OP_PLUS, OP_TIMES, OP_DIV, OP_GT,
-           OP_LT, OP_GE, OP_LE, OP_EQ, OP_ASSIGN, OP_PLUS_ASSIGN, OP_DIV_ASSIGN,
-           OP_TIMES_ASSIGN
-         };
-#   define OPERATORS "+\n* /\n> < >= <= ==\n= += /= *="
-    enum { COMMENT_UNDEF, COMMENT_1, COMMENT_MULTILINE, COMMENT_2
-    };
-#   define COMMENTS "/* */ // \n"
-    void testSpace(){
-        ReSource source;
-        ReStringReader reader(source);
-#       define BLANKS1 "\t\t   \n"
-#       define BLANKS2 " \n"
-        reader.addSource("<main>", BLANKS1 BLANKS2);
-        source.addReader(&reader);
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_DECIMAL,
-                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS1);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS2);
-    }
-    void testNumeric(){
-        ReSource source;
-        ReStringReader reader(source);
-        const char* blanks = "321 0x73 7.8e+5";
-        reader.addSource("<main>", blanks);
-        source.addReader(&reader);
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
-        ReToken* token = checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkEqu(321, token->asInteger());
-        token = checkToken(lex.nextNonSpaceToken(), TOKEN_NUMBER);
-        checkEqu(0x73, token->asInteger());
-        token = checkToken(lex.nextNonSpaceToken(), TOKEN_REAL);
-        checkEqu(7.8e+5, token->asReal());
-    }
-
-    void testOperators(){
-        ReSource source;
-        ReStringReader reader(source);
-        const char* ops = "<< < <<< <= == = ( ) [ ]";
-        reader.addSource("<main>", ops);
-        source.addReader(&reader);
-        enum { UNDEF, SHIFT, LT, SHIFT2, LE, EQ, ASSIGN,
-               LPARENT, RPARENT, LBRACKET, RBRACKET };
-        ReLexer lex(&source, KEYWORDS, ops, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT2);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LE);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, EQ);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, ASSIGN);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
-        reader.addSource("<buffer2>", "(([[");
-        lex.startUnit("<buffer2>");
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
-    }
-
-    void testComments(){
-        ReSource source;
-        ReStringReader reader(source);
-
-        reader.addSource("<main>", "/**/9//\n8/***/7// wow\n/*\n*\n*\n**/");
-        source.addReader(&reader);
-
-        enum { COMMENT_UNDEF, COMMENT_MULTILINE, COMMENT_1
-        };
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
-                   "/**/");
-        checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
-                   "//\n");
-        checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
-                   "/***/");
-        checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
-                   "// wow\n");
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
-                   "/*\n*\n*\n**/");
-    }
-    void testStrings(){
-        ReSource source;
-        ReStringReader reader(source);
-
-        reader.addSource("<main>", "\"abc\\t\\r\\n\\a\\v\"'1\\x9Z\\x21A\\X9'");
-        source.addReader(&reader);
-
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_STRING, '"', "abc\t\r\n\a\v");
-        checkToken(lex.nextToken(), TOKEN_STRING, '\'', "1\tZ!A\t");
-    }
-    void testKeywords(){
-        ReSource source;
-        ReStringReader reader(source);
-
-        reader.addSource("<main>", "if\n\tthen else\nfi");
-        source.addReader(&reader);
-
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_THEN);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_ELSE);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_FI);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
-    }
-
-    void testIds(){
-        ReSource source;
-        ReStringReader reader(source);
-
-        reader.addSource("<main>", "i\n\tifs\n"
-            "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-        source.addReader(&reader);
-
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
-        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
-           "ifs");
-        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
-           "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-    }
-
-    void testBasic(){
-        ReSource source;
-        ReStringReader reader(source);
-        source.addReader(&reader);
-        reader.addSource("<main>", "if i>1 then i=1+2*_x9 fi");
-        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
-        ReToken* token;
-        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
-        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
-        checkToken(lex.nextToken(), TOKEN_OPERATOR, OP_GT);
-        token = checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkEqu(1, token->asInteger());
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
-        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_THEN);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
-
-    }
-    void testPrio(){
-        ReSource source;
-        ReStringReader reader(source);
-        source.addReader(&reader);
-        reader.addSource("x", "");
-        enum { O_UNDEF, O_ASSIGN, O_PLUS, O_MINUS, O_TIMES, O_DIV
-             };
-        ReLexer lex(&source, KEYWORDS,
-                     "=\n+ -\n* /", "=",
-                 COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 ReLexer::NUMTYPE_ALL,
-                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
-        checkT(lex.prioOfOp(O_ASSIGN) < lex.prioOfOp(O_PLUS));
-        checkEqu(lex.prioOfOp(O_PLUS), lex.prioOfOp(O_MINUS));
-        checkT(lex.prioOfOp(O_MINUS) < lex.prioOfOp(O_TIMES));
-        checkEqu(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV));
-    }
-
-    virtual void doIt(void) {
-        testPrio();
-        testBasic();
-        testIds();
-        testKeywords();
-        testComments();
-        testStrings();
-        testOperators();
-        testNumeric();
-        testSpace();
-        testRplToken();
-    }
-};
-void testRplLexer() {
-    TestRplLexer test;
-    test.run();
-}
diff --git a/cunit/rplmatrix_test.cpp b/cunit/rplmatrix_test.cpp
deleted file mode 100644 (file)
index 2b30e7a..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * rplmatrix_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 matrices.
- */
-
-#include "base/rebase.hpp"
-#include "rplmath/rplmath.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplMatrix : public ReTest{
-public:
-    TestRplMatrix() : ReTest("RplMatrix") {}
-
-public:
-    void fillMatrix(RplMatrix& mx, MatVal offset = 0){
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                mx.set(row, col, 100.0*row + col + offset);
-            }
-        }
-    }
-    void checkMatrix(const RplMatrix& mx, MatVal offset = 0){
-        int count = 0;
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                checkEqu(100.0*row + col + offset, mx.get(row, col));
-                count++;
-            }
-        }
-        checkEqu(mx.getCols()*mx.getRows(), count);
-    }
-    void fillConst(RplMatrix& mx, MatVal value){
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                mx.set(row, col, value);
-            }
-        }
-    }
-    void checkConst(const RplMatrix& mx, MatVal value){
-        int count = 0;
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                checkEqu(value, mx.get(row, col));
-                count++;
-            }
-        }
-        checkEqu(mx.getCols()*mx.getRows(), count);
-    }
-
-    void testBasic() {
-        Tuple2 tuple(-2.0, 0.5);
-        checkEqu(-2.0, tuple.m_value1);
-        checkEqu(0.5, tuple.m_value2);
-        RplMatrix mat("mx");
-        try{
-            throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (RplMatrixException exc){
-            checkEqu("mx: String: Hi and int -333", exc.getMessage());
-        }
-        RplMatrix mat2;
-        try{
-            throw RplMatrixException(mat2, "String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (RplMatrixException exc){
-            checkEqu("String: Hi and int -333", exc.getMessage());
-        }
-        checkEqu("mx", mat.getName());
-        checkEqu("", mat2.getName());
-
-        RplMatrix m2x3(2, 3, "m2x3");
-        checkEqu("m2x3", m2x3.getName());
-        checkEqu(2, m2x3.getRows());
-        checkEqu(3, m2x3.getCols());
-        fillMatrix(m2x3);
-        checkMatrix(m2x3);
-
-        RplMatrix mxCopy(m2x3);
-        checkEqu("m2x3-copy", mxCopy.getName());
-        checkEqu(2, mxCopy.getRows());
-        checkEqu(3, mxCopy.getCols());
-        checkMatrix(mxCopy);
-
-        RplMatrix mxCopy2("mxCopy2");
-        mxCopy2 = m2x3;
-        checkEqu("mxCopy2", mxCopy2.getName());
-        checkEqu(2, mxCopy2.getRows());
-        checkEqu(3, mxCopy2.getCols());
-        checkMatrix(mxCopy2);
-    }
-    void testAddOperators(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(3, 2, "m2");
-        fillMatrix(m2, 42);
-        checkMatrix(m2, 42);
-        RplMatrix m3(3, 2, "m3");
-        fillMatrix(m3, -42);
-        checkMatrix(m3, -42);
-
-        m1 += 42;
-        checkMatrix(m1, 42);
-
-        checkT(m1 == m2);
-        checkF(m1 == m3);
-
-        m1 -= 42;
-        checkMatrix(m1);
-        m1 -= m1;
-        checkConst(m1, 0);
-
-        fillMatrix(m1);
-        m1 -= m3;
-        checkConst(m1, 42);
-        m1 += m2;
-        checkMatrix(m1, 42*2);
-    }
-    void testCompareOperators(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(3, 2, "m2");
-        fillMatrix(m2);
-
-        checkT(m1 == m2);
-        checkF(m1 != m2);
-        // modify each element, comparism must return false:
-        int row, col;
-        for (row = 0; row < m2.getRows(); row++)
-            for (col = 0; col < m2.getCols(); col++){
-                fillMatrix(m2);
-                m2.set(row, col, -1);
-                checkF(m1 == m2);
-                checkT(m1 != m2);
-            }
-
-        fillConst(m1, 42);
-        checkT(m1 == 42);
-        checkF(m1 == 43);
-        checkT(m1 != 43);
-        for (row = 0; row < m1.getRows(); row++)
-            for (col = 0; col < m1.getCols(); col++){
-                fillMatrix(m1, 42);
-                m1.set(row, col, -1);
-                checkF(m1 == 42);
-                checkT(m1 != 42);
-            }
-    }
-
-    void testCheckDefinition(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(3, 2, "m2");
-        fillMatrix(m2);
-
-        m1.checkDefinition(1, 1);
-        m1.checkDefinition(1000, 1000);
-        m1.checkDefinition(0, 0);
-        try {
-            m1.checkDefinition(-1, 1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: row number negative: -1", exc.getMessage());
-        }
-        try {
-            m1.checkDefinition(1, -1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: column number negative: -1", exc.getMessage());
-        }
-
-    }
-    void testCheck(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-
-        m1.check(0, 0);
-        m1.check(3-1, 2-1);
-        try {
-            m1.check(-1, 1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: invalid row: -1 not in [0,3[", exc.getMessage());
-        }
-        try {
-            m1.check(3, 1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: invalid row: 3 not in [0,3[", exc.getMessage());
-        }
-        try {
-            m1.check(1, -1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: invalid column: -1 not in [0,2[", exc.getMessage());
-        }
-        try {
-            m1.check(1, 2);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: invalid column: 2 not in [0,2[", exc.getMessage());
-        }
-    }
-    void testCheckSameDimension(){
-        RplMatrix m1(3, 2, "m1");
-        RplMatrix m2(3, 2, "m2");
-
-        m1.checkSameDimension(m2);
-
-        m2.resize(2, 2);
-        try {
-            m1.checkSameDimension(m2);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: m2 has a different row count: 3 / 2", exc.getMessage());
-        }
-        m2.resize(3, 3);
-        try {
-            m1.checkSameDimension(m2);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkEqu("m1: m2 has a different column count: 2 / 3", exc.getMessage());
-        }
-    }
-    void testResize(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(2, 4, "m2");
-        fillConst(m2, 0);
-        checkConst(m2, 0);
-
-        m1.resize(2, 4);
-        checkEqu(2, m1.getRows());
-        checkEqu(4, m1.getCols());
-        checkT(m1 == m2);
-    }
-
-    void testMinMax(){
-        RplMatrix m1(4, 5, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        m1.set(0, 0, -98);
-        m1.set(3, 4, 9999);
-        Tuple2 miniMax = m1.minMax();
-        checkEqu(-98.0, miniMax.m_value1);
-        checkEqu(9999.0, miniMax.m_value2);
-
-        fillMatrix(m1);
-        checkMatrix(m1);
-        m1.set(1, 1, 7777);
-        m1.set(3, 4, -987);
-        miniMax = m1.minMax();
-        checkEqu(-987.0, miniMax.m_value1);
-        checkEqu(7777.0, miniMax.m_value2);
-    }
-
-    void testTranspose()
-    {
-        RplMatrix m1(1, 5, "m1");
-        fillMatrix(m1);
-        RplMatrix m2(m1.transpose());
-
-        checkEqu(5, m2.getRows());
-        checkEqu(1, m2.getCols());
-
-        int row, col;
-        col = 0;
-        for (row = 0; row < 5; row++){
-            checkEqu(qreal(col*100+row), m2.get(row, 0));
-        }
-
-        m1.resize(35, 73);
-        fillMatrix(m1);
-        m2 = m1.transpose();
-
-        checkEqu(73, m2.getRows());
-        checkEqu(35, m2.getCols());
-
-        int count = 0;
-        for (row = 0; row < m2.getRows(); row++){
-            for (col = 0; col < m2.getCols(); col++){
-                checkEqu(qreal(col*100+row), m2.get(row, col));
-                count++;
-            }
-        }
-        checkEqu(73*35, count);
-    }
-    void testToString(){
-        RplMatrix m1(1, 1, "m1");
-        m1.set(0, 0, 2.34);
-        checkEqu("[2.340000,\n]", m1.toString().constData());
-        checkEqu("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
-
-        m1.resize(2, 1);
-        m1.set(0, 0, 2.34);
-        m1.set(1, 0, 55.5);
-
-        checkEqu("[2.340000,\n55.500000,\n]", m1.toString().constData());
-        checkEqu("jonny[2.34000 |55.50000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
-        log("");
-    }
-    void testReadCsv(){
-        QByteArray fn = getTempFile("rplmatrixtest.csv");
-        const char* content;
-        RplMatrix m1(1,1,"m1");
-
-        fillMatrix(m1);
-        content = ",Port0,Port1,Port2\n"
-                "element1,5,  -3E-99  , 0.5\n"
-                "element2,7,-22.3,44\n"
-                "\n"
-                "2 Elements, 3, Ports";
-        ReStringUtil::write(fn, content);
-        m1.readFromCvs(fn, 256);
-        checkEqu(2, m1.getRows());
-        checkEqu(3, m1.getCols());
-
-        checkEqu(5.0, m1.get(0, 0));
-        checkEqu(-3.0E-99, m1.get(0, 1));
-        checkEqu(0.5, m1.get(0, 2));
-
-        checkEqu(7.0, m1.get(1, 0));
-        checkEqu(-22.3, m1.get(1, 1));
-        checkEqu(44.0, m1.get(1, 2));
-
-        fillMatrix(m1);
-        content = "Port0,Port1,Port2\n"
-                "5,  -3E-99  , 0.5\n";
-        ReStringUtil::write(fn, content);
-        m1.readFromCvs(fn, 256);
-        checkEqu(1, m1.getRows());
-        checkEqu(3, m1.getCols());
-        checkEqu(5.0, m1.get(0, 0));
-        checkEqu(-3.0E-99, m1.get(0, 1));
-        checkEqu(0.5, m1.get(0, 2));
-
-
-/*
-    void readFromCvs(const char* filename, int maxLineLength = 1024*1024);
-    void readFromXml(const char* filename, const char* tagCol,
-            const char* tagRow, const char* tagTable,
-            int maxLineLength = 1024*1024);
-*/
-    }
-    virtual void doIt(void) {
-        testBasic();
-        testAddOperators();
-        testCompareOperators();
-        testCheckDefinition();
-        testCheck();
-        testCheckSameDimension();
-        testResize();
-        testMinMax();
-        testTranspose();
-        testToString();
-        testReadCsv();
-    }
-};
-void testRplMatrix() {
-    TestRplMatrix test;
-    test.run();
-}
diff --git a/cunit/rplmfparser_test.cpp b/cunit/rplmfparser_test.cpp
deleted file mode 100644 (file)
index a234542..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * rplmfparser_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 parser for the language "MF".
- */
-
-#include "base/rebase.hpp"
-#include "expr/reexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplMFParser : public ReTest{
-private:
-    ReSource m_source;
-    ReASTree m_tree;
-    ReStringReader m_reader;
-    ReFileReader m_fileReader;
-    QByteArray m_currentSource;
-public:
-    TestRplMFParser() :
-        ReTest("ReMFParser"),
-        m_source(),
-        m_tree(),
-        m_reader(m_source),
-        m_fileReader(m_source)
-    {
-        m_source.addReader(&m_reader);
-    }
-protected:
-    void setSource(const char* content){
-        ReASItem::reset();
-        m_currentSource = content;
-        m_tree.clear();
-        m_source.clear();
-        m_reader.clear();
-        m_reader.addSource("<test>", content);
-        m_source.addReader(&m_reader);
-        m_source.addSourceUnit(m_reader.currentSourceUnit());
-    }
-    void setFileSource(const char* filename){
-        ReASItem::reset();
-        m_currentSource = ReStringUtil::read(filename);
-        m_tree.clear();
-        m_source.clear();
-        m_fileReader.clear();
-        m_fileReader.addSource(filename);
-        m_source.addReader(&m_fileReader);
-        m_source.addSourceUnit(m_fileReader.currentSourceUnit());
-    }
-
-private:
-    void checkAST(const char* fileExpected, int lineNo){
-        QByteArray fnExpected = "test";
-        fnExpected += QDir::separator().toLatin1();
-        fnExpected += "mfparser";
-        fnExpected += (char) QDir::separator().toLatin1();
-        fnExpected += fileExpected;
-        QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser");
-        m_tree.dump(fnCurrent, ReASTree::DMP_NO_GLOBALS, m_currentSource);
-        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
-                         __FILE__, lineNo);
-    }
-
-public:
-    void fileClassTest(){
-        setFileSource("test/rplmfparser/string1.mf");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("string1.txt", __LINE__);
-    }
-
-    void baseTest(){
-        setSource("2+3*4");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("baseTest.txt", __LINE__);
-    }
-
-    void varDefTest(){
-        setSource("const lazy Str s = 'Hi';\nconst List l;\nInt i = 3;");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("varDefTest.txt", __LINE__);
-    }
-
-    void ifTest(){
-        setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi");
-        // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("ifTest1.txt", __LINE__);
-        setSource("Str x;\nif 7 < 6\nthen x = '123';\nfi");
-        parser.parse();
-        checkAST("ifTest2.txt", __LINE__);
-    }
-    void whileTest(){
-        setSource("Int a = 20;\nwhile 3 < 5 do\n a = 7\nod");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("whileTest.txt", __LINE__);
-    }
-
-    void repeatTest(){
-        setSource("Int a;\nrepeat\na++;\nuntil a != 2 * 3;");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("repeatTest.txt", __LINE__);
-    }
-    void forCTest(){
-        setSource("Int a;\nfor b from 10 to 1 step -2 do\na += 1;\nod");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("forC1.txt", __LINE__);
-        setSource("Int a; for to 10 do a += 1 od");
-        parser.parse();
-        checkAST("forC2.txt", __LINE__);
-    }
-    void opTest(){
-        checkEqu(25, ReMFParser::O_QUESTION);
-        checkEqu(37, ReMFParser::O_RSHIFT2);
-        checkEqu(41, ReMFParser::O_DEC);
-        checkEqu(48, ReMFParser::O_RBRACE);
-        setSource("Int a = 1;\nInt b = 100;\n--a;\nb++;\na--*++b**(8-3);\na=b=(a+(b-2)*3)");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("opTest1.txt", __LINE__);
-    }
-    void forItTest(){
-        setSource("Map a;\nfor x in a do\na += 1;\nod");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("forIt1.txt", __LINE__);
-    }
-    void listTest(){
-        ReMFParser parser(m_source, m_tree);
-        setSource("List b = [];");
-        parser.parse();
-        checkAST("list1.txt", __LINE__);
-        setSource("List a = [2+3, 3.14, 7, 'hi', a]; List b = [];");
-        parser.parse();
-        checkAST("list2.txt", __LINE__);
-    }
-    void mapTest(){
-        setSource("Map a = {};");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("map1.txt", __LINE__);
-        setSource("Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};\nMap b = {};");
-        parser.parse();
-        checkAST("map2.txt", __LINE__);
-    }
-    void methodCallTest(){
-        //setSource("max(4,3.14);");
-        setSource("rand();\nsin(a);\nmax(1+2*3,4**(5-4));");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("methc1.txt", __LINE__);
-    }
-    void fieldTest(){
-        setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("field1.txt", __LINE__);
-    }
-
-    void methodTest(){
-        setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("meth1.txt", __LINE__);
-        setSource("func Int fac(const Int n):\n"
-                  "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n"
-                  "rc endf");
-        parser.parse();
-        checkAST("meth2.txt", __LINE__);
-        setSource("func Int max(Int a, Int b):\n Int rc = a;\n"
-                  "if a < b then rc = b; fi\nrc\n"
-                  "endf\n"
-                  "func Int max(const Int a, Int b, Int c):\n"
-                  "max(a, max(b, c))\n"
-                  "endf");
-        parser.parse();
-        checkAST("meth3.txt", __LINE__);
-        setSource("func Int max(const Int a, Int b, Int c):\n"
-                  "func Int max(Int a, Int b):\n Int rc = a;\n"
-                  "if a < b then rc = b; fi\nrc\n"
-                  "endf\n"
-                  "max(a, max(b, c))\n"
-                  "endf");
-        parser.parse();
-        checkAST("meth4.txt", __LINE__);
-    }
-    void mainTest(){
-        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("main1.txt", __LINE__);
-    }
-
-    virtual void doIt(void) {
-        mainTest();
-        varDefTest();
-        repeatTest();
-        baseTest();
-        whileTest();
-        methodTest();
-        fieldTest();
-        methodCallTest();
-        mapTest();
-        forItTest();
-        forCTest();
-        listTest();
-        opTest();
-        fileClassTest();
-    }
-};
-void testRplMFParser() {
-    TestRplMFParser test;
-    test.run();
-}
-
-
diff --git a/cunit/rplqstring_test.cpp b/cunit/rplqstring_test.cpp
deleted file mode 100644 (file)
index d6116f5..0000000
+++ /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/cunit/rplsource_test.cpp b/cunit/rplsource_test.cpp
deleted file mode 100644 (file)
index 83fd0ec..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * rplsource_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 input media reader.
- */
-
-#include "base/rebase.hpp"
-#include "expr/reexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestReSource : public ReTest{
-public:
-    TestReSource() : ReTest("TestReSource") {}
-
-private:
-    QByteArray m_content1_1;
-    QByteArray m_content1_2;
-    QByteArray m_content2;
-    ReSource m_source;
-
-protected:
-    void init(){
-        m_content1_1 = "# test\nimport source2\n";
-        m_content1_2 = "a=1;\nveeeeeeeeery looooooooooooooong\n";
-        m_content2 = "x=2";
-    }
-
-    void testReStringSourceUnit(){
-        ReStringReader reader(m_source);
-        QByteArray content("a=1;\nveeeeeeeeery looooooooooooooong\n");
-        ReStringSourceUnit unit("test", content, &reader);
-        unit.setLineNo(144);
-        checkEqu(144, unit.lineNo());
-        checkEqu("test", unit.name());
-    }
-    void checkOne(int maxSize, ReReader& reader){
-        QByteArray total;
-        QByteArray buffer;
-        int lineNo = 0;
-        bool hasMore;
-        checkF(reader.openSourceUnit("unknownSource"));
-        checkT(reader.openSourceUnit("source1"));
-        while(reader.nextLine(maxSize, buffer, hasMore)){
-            lineNo++;
-            total += buffer;
-            buffer.clear();
-            while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
-                total += buffer;
-                buffer.clear();
-            }
-            bool isImport = total.endsWith("source2\n");
-            if (isImport){
-                reader.openSourceUnit("source2");
-                checkEqu("source2", reader.currentSourceUnit()->name());
-                while(reader.nextLine(maxSize, buffer, hasMore)){
-                    lineNo++;
-                    while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
-                        total += buffer;
-                        buffer.clear();
-                    }
-                }
-                checkEqu("source1", reader.currentSourceUnit()->name());
-            }
-        }
-        checkEqu(5, lineNo);
-        checkEqu(m_content1_1 + m_content2 + m_content1_2, total);
-
-    }
-
-    void testReStringReader(){
-        ReStringReader reader(m_source);
-        reader.addSource("source1", m_content1_1 + m_content1_2);
-        reader.addSource("source2", m_content2);
-        ReSourceUnit* unit = reader.openSourceUnit("source1");
-        checkNN(unit);
-        checkEqu("source1", unit->name());
-        checkEqu(0, unit->lineNo());
-        checkOne(6, reader);
-        checkOne(100, reader);
-        reader.replaceSource("source2", "content2");
-
-        unit = reader.openSourceUnit("source2");
-        QByteArray buffer;
-        bool hasMore;
-        checkT(reader.nextLine(50, buffer, hasMore));
-        checkEqu("content2", buffer);
-        checkF(hasMore);
-    }
-
-public:
-    virtual void doIt(void) {
-        init();
-        testReStringSourceUnit();
-        testReStringReader();
-    }
-};
-void testReSource() {
-    TestReSource test;
-    test.run();
-}
-
-
-
diff --git a/cunit/rplstring_test.cpp b/cunit/rplstring_test.cpp
deleted file mode 100644 (file)
index c2e7dc8..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * rplstring_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 QByteArray tools.
- */
-#include "base/rebase.hpp"
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test for <code>ReStringUtil</code>.
- */
-class TestReString : public ReTest {
-public:
-    TestReString() : ReTest("ReStringUtil") {}
-
-public:
-    void testCountChar(){
-        checkEqu(1, ReStringUtil::countChar("x", 'x'));
-        checkEqu(0, ReStringUtil::countChar("X", 'x'));
-        checkEqu(2, ReStringUtil::countChar("xbxxbxx", 'b'));
-    }
-
-    void testCount() {
-        checkEqu(0, ReStringUtil::count("abc", " "));
-        checkEqu(1, ReStringUtil::count("abc", "b"));
-        checkEqu(2, ReStringUtil::count("axx", "x"));
-
-        checkEqu(0, ReStringUtil::count("abbc", "bbb"));
-        checkEqu(1, ReStringUtil::count("\n\n", "\n\n"));
-        checkEqu(2, ReStringUtil::count("  a  ", "  "));
-    }
-
-    void testCutString() {
-        QByteArray source("123");
-        QByteArray buffer;
-        checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 4, buffer));
-        checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 3, buffer));
-        checkEqu(QByteArray("12..."), ReStringUtil::cutString(source, 2, buffer));
-        checkEqu(QByteArray("12"), ReStringUtil::cutString(source, 2, buffer, ""));
-    }
-
-    void testHexDump() {
-        QByteArray data("abc123\nxyz");
-        checkEqu(QByteArray("61 62 63 31  abc1\n"
-                          "32 33 0a 78  23.x\n"
-                          "79 7a        yz\n"),
-               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 4));
-        checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a  abc123.xyz"),
-               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 10));
-        checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a        abc123.xyz"),
-               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 12));
-    }
-
-    void testReadWrite() {
-        QByteArray fn = getTempFile("test.dat");
-        const char* content = "Hello world\nLine2\n";
-        checkT(ReStringUtil::write(fn, content));
-        checkEqu(content, ReStringUtil::read(fn, false));
-        checkEqu(content, ReStringUtil::read(fn, true) + "\n");
-    }
-
-    void testToArray() {
-        QList<QByteArray> array = ReStringUtil::toArray("1 abc 3", " ");
-        checkEqu(3, array.size());
-        checkEqu("1", array.at(0));
-        checkEqu("abc", array.at(1));
-        checkEqu("3", array.at(2));
-    }
-
-    void testToNumber() {
-        checkEqu("3", ReStringUtil::toNumber(3));
-        checkEqu("-33", ReStringUtil::toNumber(-33));
-        checkEqu("003", ReStringUtil::toNumber(3, "%03d"));
-    }
-
-    void testLengthOfNumber(){
-        checkEqu(3, ReStringUtil::lengthOfNumber("0.3xxx"));
-        checkEqu(5, ReStringUtil::lengthOfNumber(" \t0.3xxx"));
-        checkEqu(3, ReStringUtil::lengthOfNumber("-.3xxx"));
-        checkEqu(2, ReStringUtil::lengthOfNumber(".3exxx"));
-        checkEqu(2, ReStringUtil::lengthOfNumber(".3e+xxx"));
-        checkEqu(16, ReStringUtil::lengthOfNumber("1234567.9012E+77"));
-        checkEqu(17, ReStringUtil::lengthOfNumber("-1234567.9012E+77 "));
-        checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ", true));
-        checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 x", true));
-        checkEqu(20, ReStringUtil::lengthOfNumber("  -1234567.9012E+77 x", true));
-    }
-
-    void checkCsv(const char* content, char expected){
-        QByteArray fn = getTempFile("testrplstring.csv");
-        ReStringUtil::write(fn, content);
-        FILE* fp = fopen(fn, "r");
-        checkNN(fp);
-        char buffer[256];
-        checkEqu(expected, ReStringUtil::findCsvSeparator(fp, buffer, sizeof buffer));
-        fclose(fp);
-    }
-
-    void testFindCsvSeparator(){
-        const char* content = ",,,\t;;;||||";
-        checkCsv(content, '\t');
-
-        content = "col1,col2\n1.5,3,5\n";
-        checkCsv(content, ',');
-
-        content = "col1;col2\n1,50;3.5\n"
-                 "7;8\n10;12\n13;14";
-        checkCsv(content, ';');
-
-        content = "0.3 7.8 8.9\n7.8 9.4 8.3";
-        checkCsv(content, ' ');
-
-        content = "0.3|7.8|8.9\n7.8|         9.4|8.3";
-        checkCsv(content, '|');
-
-        content = "0,3;7.8;8.9";
-        checkCsv(content, ';');
-    }
-    void testLengthOfUInt64(){
-        quint64 value = -3;
-        checkEqu(1, ReStringUtil::lengthOfUInt64("0", 10, &value));
-        checkEqu(0LL, value);
-        checkEqu(3, ReStringUtil::lengthOfUInt64("432", 10, &value));
-        checkEqu(432LL, value);
-        checkEqu(3, ReStringUtil::lengthOfUInt64("432 x", 10, &value));
-        checkEqu(432LL, value);
-        checkEqu(3, ReStringUtil::lengthOfUInt64("432fabc x", 10, &value));
-        checkEqu(432LL, value);
-        checkEqu(16, ReStringUtil::lengthOfUInt64("1234567890123567", 10, &value));
-        checkEqu(1234567890123567LL, value);
-        checkEqu(10, ReStringUtil::lengthOfUInt64("1234abcdef", 16, &value));
-        checkEqu(0x1234abcdefLL, value);
-        checkEqu(3, ReStringUtil::lengthOfUInt64("432", 8, &value));
-        checkEqu(0432LL, value);
-        checkEqu(6, ReStringUtil::lengthOfUInt64("765432 ", 8, &value));
-        checkEqu(0765432LL, value);
-
-        checkEqu(0, ReStringUtil::lengthOfUInt64(" ", 8, &value));
-        checkEqu(0, ReStringUtil::lengthOfUInt64("", 8, &value));
-    }
-    void testLengthOfReal(){
-        qreal value;
-        checkEqu(1, ReStringUtil::lengthOfReal("0", &value));
-        checkEqu(0.0, value);
-        checkEqu(1, ReStringUtil::lengthOfReal("0%", &value));
-        checkEqu(0.0, value);
-        checkEqu(4, ReStringUtil::lengthOfReal("0.25", &value));
-        checkEqu(0.25, value);
-        checkEqu(3, ReStringUtil::lengthOfReal(".25", &value));
-        checkEqu(0.25, value);
-        checkEqu(17, ReStringUtil::lengthOfReal("12345678901234567", &value));
-        checkEqu(12345678901234567.0, value);
-        checkEqu(2, ReStringUtil::lengthOfReal(".5", &value));
-        checkEqu(0.5, value);
-        checkEqu(5, ReStringUtil::lengthOfReal("2.5e2x", &value));
-        checkEqu(250.0, value);
-        checkEqu(6, ReStringUtil::lengthOfReal("2.5e+2", &value));
-        checkEqu(250.0, value);
-        checkEqu(7, ReStringUtil::lengthOfReal("2.5E-33", &value));
-        checkEqu(2.5e-33, value);
-
-        checkEqu(3, ReStringUtil::lengthOfReal("2.5E", &value));
-        checkEqu(2.5, value);
-        checkEqu(3, ReStringUtil::lengthOfReal("2.5E+", &value));
-        checkEqu(2.5, value);
-        checkEqu(3, ReStringUtil::lengthOfReal("2.5E-a", &value));
-        checkEqu(2.5, value);
-    }
-
-    virtual void doIt() {
-        testLengthOfReal();
-        testLengthOfUInt64();
-        testCountChar();
-        testCount();
-        testCutString();
-        testToNumber();
-        testToArray();
-        testHexDump();
-        testReadWrite();
-        testLengthOfNumber();
-        testFindCsvSeparator();
-    }
-};
-
-void testReString() {
-    TestReString test;
-    test.run();
-}
-
-
-
diff --git a/cunit/rplvm_test.cpp b/cunit/rplvm_test.cpp
deleted file mode 100644 (file)
index 39df487..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * rplvm_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
- */
-
-#include "base/rebase.hpp"
-#include "expr/reexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestReVM : public ReTest{
-private:
-    ReSource m_source;
-    ReASTree m_tree;
-    ReStringReader m_reader;
-    const char* m_currentSource;
-public:
-    TestReVM() :
-        ReTest("ReVM"),
-        m_source(),
-        m_tree(),
-        m_reader(m_source)
-    {
-        m_source.addReader(&m_reader);
-    }
-protected:
-    void setSource(const char* content){
-        ReASItem::reset();
-        m_currentSource = content;
-        m_tree.clear();
-        m_source.clear();
-        m_reader.clear();
-        m_reader.addSource("<test>", content);
-        m_source.addReader(&m_reader);
-        m_source.addSourceUnit(m_reader.currentSourceUnit());
-    }
-
-private:
-    void checkAST(const char* fileExpected, int lineNo){
-        QByteArray fnExpected = "test";
-        fnExpected += QDir::separator().toLatin1();
-        fnExpected += "ReVM";
-        fnExpected += (char) QDir::separator().toLatin1();
-        fnExpected += fileExpected;
-        QByteArray fnCurrent = getTempFile(fileExpected, "ReVM");
-        ReMFParser parser(m_source, m_tree);
-        parser.parse();
-        ReVirtualMachine vm(m_tree, m_source);
-        vm.setFlag(ReVirtualMachine::VF_TRACE_STATEMENTS);
-        ReFileWriter writer(fnCurrent);
-        vm.setTraceWriter(&writer);
-        writer.write(m_currentSource);
-        vm.executeModule("<test>");
-        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
-                         __FILE__, lineNo);
-    }
-public:
-    void baseTest(){
-        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
-        checkAST("baseTest.txt", __LINE__);
-    }
-    virtual void doIt(void) {
-        baseTest();
-    }
-};
-void testReVM() {
-    TestReVM test;
-    test.run();
-}
-
diff --git a/cunit/rplwriter_test.cpp b/cunit/rplwriter_test.cpp
deleted file mode 100644 (file)
index 71de3b6..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * rplwriter_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 output media writers.
- */
-
-#include "base/rebase.hpp"
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test for <code>ReStringUtil</code>.
- */
-class TestRplWriter : public ReTest {
-public:
-    TestRplWriter() : ReTest("ReWriter") {}
-
-private:
-    void testFileWriter(){
-        QByteArray fn = getTempFile("rplwriter.txt");
-        ReFileWriter writer(fn);
-        writer.writeLine("abc");
-        writer.formatLine("%04d", 42);
-        writer.writeIndented(3, "123");
-        writer.indent(2);
-        writer.write("pi");
-        writer.format("%3c%.2f", ':', 3.1415);
-        writer.writeLine();
-        writer.close();
-        QByteArray current = ReStringUtil::read(fn, false);
-        checkEqu("abc\n0042\n\t\t\t123\n\t\tpi  :3.14\n", current);
-    }
-
-public:
-    virtual void doIt(void) {
-        testFileWriter();
-    }
-};
-void testRplWriter() {
-    TestRplWriter test;
-    test.run();
-}
-
-
-
index 3aab1217ff79e86065f9ba5661d5f6aa7d7e8dc4..e9d814bb8e9da5f9fcb8caf049f092726b9774e3 100644 (file)
@@ -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;
index 7321dd3ad19571278f944f63791db5824be9796f..1fabfe5aa4cbc2a6ace3b1866cbcaee33dc7ff76 100644 (file)
 #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 {
index 578d196c4d1f55f4929e9bb9c5bf6a3251c5fb33..c236037dc3954ff9d56ed6aa3d4fa2c20049dc6f 100644 (file)
 #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:
index 06c2fb8d9a6a3caf418b2ba67d6b7e246ebc9a94..4b9d1495b476b96d0b82a76e0735d4b49a68e110 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ReTCPServer.hpp
- * 
+ *
  * License: Public Domain
  * You can use and modify this file without any restriction.
  * Do what you want.
 #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 (file)
index 0000000..e9b4d39
--- /dev/null
@@ -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          <code>buffer.str()</code> (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                     <code>buffer.str()</code>, 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     <code>true</code>: 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     <code>true</code>: 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 <code>CreateFile()</code>)
+ * @param name         OUT: the owner: [domain\\]name
+ * @return                     <code>true</code>: 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     <code>true</code>: 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     <code>true</code>: 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     <code>true</code>: 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     <code>true</code>: 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            <code>true</code>: the owner/group should be numerical (UID/GID)
+ * @param ownerWidth   the width for group/owner
+ * @return                             <code>buffer.str()</code> (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 <code>sequence</code>
+ */
+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                     <true>: the entry matches the conditions of the filter<br>
+ *                                     <false>: 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               <code>true</code>: the string will be appended to the buffer<br>
+ *                                             <code>false</code>: the buffer will be cleared at the beginning
+ * @param formatFiles  the <code>sprintf</code> format for the file count, e.g. "%8d"
+ * @param formatSized  the <code>sprintf</code> format for the MByte format, e.g. "%12.6f"
+ * @param formatFiles  the <code>sprintf</code> 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                     <code>true</code> (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.<br>
+ *                                     0 means the file is inside the base.<br>
+ *                                     Not defined if the result is NULL
+ * @return NULL        no more files<br>
+ *                                     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.<br>
+ *                                     0 means the file is inside the base.<br>
+ *                                     Not defined if the result is NULL
+ * @param filter       NULL: every file matches<br>
+ *                                     otherwise: each found file must match this filter conditions
+ * @return NULL        no more files<br>
+ *                                     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.<br>
+ *                  If < 0: m_levels and m_path will not be changed
+ * @return          <code>true</code>: a new file is available<br>
+ *                  <cude>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<br>
+ *                                                     1: returns the entry one below the top<br>
+ *                                                     2: ...
+ * @return                                     NULL: not available<br>
+ *                                                     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 (file)
index 0000000..241b913
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/stat.h>
+
+typedef DIR* FindFileHandle_t;
+#endif
+/** Returns whether a filetime is undefined.
+ * @param time the filetime to test
+ * @return             <code>true</code>: 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 <code>true</code>: the counter has reached <code>m_triggerCount</code>
+        */
+       inline bool isCountTriggered() {
+               bool rc = ++m_count % m_triggerCount == 0;
+               return rc;
+       }
+       /** Tests whether a given waiting time has been gone since the last trace.
+        * @return      <code>true</code>: the last trace has been done after
+        *                      at least <code>m_interval</code> seconds
+        */
+       inline bool isTimeTriggered() {
+               time_t now = time(NULL);
+               bool rc = now - m_lastTrace > m_interval;
+               if (rc) {
+                       m_lastTrace = now;
+               }
+               return rc;
+       }
+       virtual bool trace(const char* message);
+protected:
+       int m_count;
+       int m_triggerCount;
+       time_t m_lastTrace;
+       int m_interval;
+       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                      <code>true</code>: 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    <code>true</code>: 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                      <code>true</code>: the subdir will be processed<br>
+        *                                      <code>false</code>: 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 (file)
index 0000000..342a9f1
--- /dev/null
@@ -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 <dirent.h>
+#include <grp.h>
+#include <pwd.h>
+#elif defined __WIN32__
+#include <tchar.h>
+#include "windows.h"
+#include <winnt.h>
+#else
+#error "unknown os"
+#endif
+
+/** Returns whether a time is greater (younger) than another.
+ * @param time1                first operand
+ * @param time2                second operand
+ * @return                     <code>true</code>: 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_ */
index ea53cad357934cef1806a0a624a6055428483810..ecc71cc97625b8171bc14764fa66628d6297f313 100644 (file)
@@ -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/ReStaticLib.cpp b/static/ReStaticLib.cpp
new file mode 100644 (file)
index 0000000..487cb56
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * rplstaticlib.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
+ */
+
+
+int main(int argc, char** argv){
+    void allTests();
+    allTests();
+}
index 82c9e9b84c48a91da874020ceefd5a225ca3a438..1ab5aa36c2677d7fba37d3fb571cffccf4f018cf 100644 (file)
@@ -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.cpp b/static/rplstaticlib.cpp
deleted file mode 100644 (file)
index 0dc5255..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * rplstaticlib.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 "../static/rplstaticlib.hpp"
-
-
-RplStaticLib::RplStaticLib()
-{
-}
diff --git a/static/rplstaticlib.hpp b/static/rplstaticlib.hpp
deleted file mode 100644 (file)
index ce4f2e3..0000000
+++ /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