From 4bb168a758e460e55d4c9b81b393bbb7e02425a2 Mon Sep 17 00:00:00 2001 From: hama Date: Fri, 10 Apr 2015 00:26:04 +0200 Subject: [PATCH] appl/refind added --- appl/refind | 1 - appl/refind/.gitignore | 2 + appl/refind/filefinder.cpp | 204 + appl/refind/filefinder.hpp | 48 + .../ReStaticLib.cpp => appl/refind/main.cpp | 17 +- appl/refind/mainwindow.cpp | 189 + appl/refind/mainwindow.hpp | 54 + appl/refind/mainwindow.ui | 429 ++ appl/refind/refind.pro | 30 + base/ReByteStorage.cpp | 165 - base/ReByteStorage.hpp | 46 - base/ReCharPtrMap.cpp | 66 - base/ReCharPtrMap.hpp | 38 - base/ReConfig.cpp | 192 - base/ReConfig.hpp | 40 - base/ReConfigurator.hpp | 21 - base/ReContainer.cpp | 457 --- base/ReContainer.hpp | 84 - base/ReException.cpp | 216 - base/ReException.hpp | 54 - base/ReLogger.cpp | 635 --- base/ReLogger.hpp | 171 - base/ReQStringUtil.cpp | 618 --- base/ReQStringUtil.hpp | 81 - base/ReStringUtil.cpp | 539 --- base/ReStringUtil.hpp | 40 - base/ReTerminator.cpp | 80 - base/ReTerminator.hpp | 32 - base/ReTest.cpp | 530 --- base/ReTest.hpp | 80 - base/ReWriter.cpp | 192 - base/ReWriter.hpp | 59 - base/rebase.hpp | 57 - base/testrplexample.cpp | 55 - bench/.gitignore | 8 - bench/mk_bench.pl | 228 -- cunit/allTests.cpp | 81 - cunit/cuReASTree.cpp | 104 - cunit/cuReBench.cpp | 63 - cunit/cuReByteStorage.cpp | 78 - cunit/cuReCharPtrMap.cpp | 36 - cunit/cuReConfig.cpp | 62 - cunit/cuReContainer.cpp | 59 - cunit/cuReEnigma.cpp | 115 - cunit/cuReException.cpp | 53 - cunit/cuReLexer.cpp | 282 -- cunit/cuReMFParser.cpp | 228 -- cunit/cuReMatrix.cpp | 374 -- cunit/cuReQStringUtil.cpp | 184 - cunit/cuReSource.cpp | 110 - cunit/cuReStringUtil.cpp | 197 - cunit/cuReTraverser.cpp | 155 - cunit/cuReVM.cpp | 74 - cunit/cuReWriter.cpp | 50 - cunit/unittests.pro | 49 - expr/ReASClasses.cpp | 1102 ------ expr/ReASClasses.hpp | 210 - expr/ReASTree.cpp | 3477 ----------------- expr/ReASTree.hpp | 720 ---- expr/ReLexer.cpp | 1178 ------ expr/ReLexer.hpp | 243 -- expr/ReMFParser.cpp | 1252 ------ expr/ReMFParser.hpp | 156 - expr/ReParser.cpp | 249 -- expr/ReParser.hpp | 63 - expr/ReSource.cpp | 822 ---- expr/ReSource.hpp | 227 -- expr/ReVM.cpp | 456 --- expr/ReVM.hpp | 112 - expr/reexpr.hpp | 30 - math/ReEnigma.cpp | 287 -- math/ReEnigma.hpp | 69 - math/ReMatrix.cpp | 490 --- math/ReMatrix.hpp | 105 - math/ReRandom.cpp | 132 - math/ReRandom.hpp | 36 - math/remath.hpp | 20 - net/ReNetConfig.cpp | 18 - net/ReNetConfig.hpp | 22 - net/ReTCPClient.cpp | 152 - net/ReTCPClient.hpp | 75 - net/ReTCPPeer.cpp | 359 -- net/ReTCPPeer.hpp | 85 - net/ReTCPServer.cpp | 228 -- net/ReTCPServer.hpp | 121 - net/renet.hpp | 27 - os/ReTraverser.cpp | 989 ----- os/ReTraverser.hpp | 290 -- os/reos.hpp | 48 - remodules.hpp | 35 - rpldoc.zip | Bin 2063763 -> 0 bytes static/getsrc.pl | 29 - static/rplstatic.pro | 103 - test/mfparser/baseTest.txt | 9 - test/mfparser/field1.txt | 22 - test/mfparser/forC1.txt | 23 - test/mfparser/forC2.txt | 17 - test/mfparser/forIt1.txt | 20 - test/mfparser/ifTest1.txt | 40 - test/mfparser/ifTest2.txt | 19 - test/mfparser/list1.txt | 12 - test/mfparser/list2.txt | 20 - test/mfparser/main1.txt | 26 - test/mfparser/map1.txt | 12 - test/mfparser/map2.txt | 21 - test/mfparser/meth1.txt | 11 - test/mfparser/meth2.txt | 36 - test/mfparser/meth3.txt | 32 - test/mfparser/meth4.txt | 59 - test/mfparser/methc1.txt | 25 - test/mfparser/opTest1.txt | 49 - test/mfparser/repeatTest.txt | 20 - test/mfparser/string1.mf | 3 - test/mfparser/string1.txt | 24 - test/mfparser/varDefTest.txt | 22 - test/mfparser/whileTest.txt | 21 - 116 files changed, 968 insertions(+), 21704 deletions(-) delete mode 160000 appl/refind create mode 100644 appl/refind/.gitignore create mode 100644 appl/refind/filefinder.cpp create mode 100644 appl/refind/filefinder.hpp rename static/ReStaticLib.cpp => appl/refind/main.cpp (59%) create mode 100644 appl/refind/mainwindow.cpp create mode 100644 appl/refind/mainwindow.hpp create mode 100644 appl/refind/mainwindow.ui create mode 100644 appl/refind/refind.pro delete mode 100644 base/ReByteStorage.cpp delete mode 100644 base/ReByteStorage.hpp delete mode 100644 base/ReCharPtrMap.cpp delete mode 100644 base/ReCharPtrMap.hpp delete mode 100644 base/ReConfig.cpp delete mode 100644 base/ReConfig.hpp delete mode 100644 base/ReConfigurator.hpp delete mode 100644 base/ReContainer.cpp delete mode 100644 base/ReContainer.hpp delete mode 100644 base/ReException.cpp delete mode 100644 base/ReException.hpp delete mode 100644 base/ReLogger.cpp delete mode 100644 base/ReLogger.hpp delete mode 100644 base/ReQStringUtil.cpp delete mode 100644 base/ReQStringUtil.hpp delete mode 100644 base/ReStringUtil.cpp delete mode 100644 base/ReStringUtil.hpp delete mode 100644 base/ReTerminator.cpp delete mode 100644 base/ReTerminator.hpp delete mode 100644 base/ReTest.cpp delete mode 100644 base/ReTest.hpp delete mode 100644 base/ReWriter.cpp delete mode 100644 base/ReWriter.hpp delete mode 100644 base/rebase.hpp delete mode 100644 base/testrplexample.cpp delete mode 100644 bench/.gitignore delete mode 100644 bench/mk_bench.pl delete mode 100644 cunit/allTests.cpp delete mode 100644 cunit/cuReASTree.cpp delete mode 100644 cunit/cuReBench.cpp delete mode 100644 cunit/cuReByteStorage.cpp delete mode 100644 cunit/cuReCharPtrMap.cpp delete mode 100644 cunit/cuReConfig.cpp delete mode 100644 cunit/cuReContainer.cpp delete mode 100644 cunit/cuReEnigma.cpp delete mode 100644 cunit/cuReException.cpp delete mode 100644 cunit/cuReLexer.cpp delete mode 100644 cunit/cuReMFParser.cpp delete mode 100644 cunit/cuReMatrix.cpp delete mode 100644 cunit/cuReQStringUtil.cpp delete mode 100644 cunit/cuReSource.cpp delete mode 100644 cunit/cuReStringUtil.cpp delete mode 100644 cunit/cuReTraverser.cpp delete mode 100644 cunit/cuReVM.cpp delete mode 100644 cunit/cuReWriter.cpp delete mode 100644 cunit/unittests.pro delete mode 100644 expr/ReASClasses.cpp delete mode 100644 expr/ReASClasses.hpp delete mode 100644 expr/ReASTree.cpp delete mode 100644 expr/ReASTree.hpp delete mode 100644 expr/ReLexer.cpp delete mode 100644 expr/ReLexer.hpp delete mode 100644 expr/ReMFParser.cpp delete mode 100644 expr/ReMFParser.hpp delete mode 100644 expr/ReParser.cpp delete mode 100644 expr/ReParser.hpp delete mode 100644 expr/ReSource.cpp delete mode 100644 expr/ReSource.hpp delete mode 100644 expr/ReVM.cpp delete mode 100644 expr/ReVM.hpp delete mode 100644 expr/reexpr.hpp delete mode 100644 math/ReEnigma.cpp delete mode 100644 math/ReEnigma.hpp delete mode 100644 math/ReMatrix.cpp delete mode 100644 math/ReMatrix.hpp delete mode 100644 math/ReRandom.cpp delete mode 100644 math/ReRandom.hpp delete mode 100644 math/remath.hpp delete mode 100644 net/ReNetConfig.cpp delete mode 100644 net/ReNetConfig.hpp delete mode 100644 net/ReTCPClient.cpp delete mode 100644 net/ReTCPClient.hpp delete mode 100644 net/ReTCPPeer.cpp delete mode 100644 net/ReTCPPeer.hpp delete mode 100644 net/ReTCPServer.cpp delete mode 100644 net/ReTCPServer.hpp delete mode 100644 net/renet.hpp delete mode 100644 os/ReTraverser.cpp delete mode 100644 os/ReTraverser.hpp delete mode 100644 os/reos.hpp delete mode 100644 remodules.hpp delete mode 100644 rpldoc.zip delete mode 100644 static/getsrc.pl delete mode 100644 static/rplstatic.pro delete mode 100644 test/mfparser/baseTest.txt delete mode 100644 test/mfparser/field1.txt delete mode 100644 test/mfparser/forC1.txt delete mode 100644 test/mfparser/forC2.txt delete mode 100644 test/mfparser/forIt1.txt delete mode 100644 test/mfparser/ifTest1.txt delete mode 100644 test/mfparser/ifTest2.txt delete mode 100644 test/mfparser/list1.txt delete mode 100644 test/mfparser/list2.txt delete mode 100644 test/mfparser/main1.txt delete mode 100644 test/mfparser/map1.txt delete mode 100644 test/mfparser/map2.txt delete mode 100644 test/mfparser/meth1.txt delete mode 100644 test/mfparser/meth2.txt delete mode 100644 test/mfparser/meth3.txt delete mode 100644 test/mfparser/meth4.txt delete mode 100644 test/mfparser/methc1.txt delete mode 100644 test/mfparser/opTest1.txt delete mode 100644 test/mfparser/repeatTest.txt delete mode 100644 test/mfparser/string1.mf delete mode 100644 test/mfparser/string1.txt delete mode 100644 test/mfparser/varDefTest.txt delete mode 100644 test/mfparser/whileTest.txt diff --git a/appl/refind b/appl/refind deleted file mode 160000 --- a/appl/refind +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0000000000000000000000000000000000000000 diff --git a/appl/refind/.gitignore b/appl/refind/.gitignore new file mode 100644 index 0000000..444078f --- /dev/null +++ b/appl/refind/.gitignore @@ -0,0 +1,2 @@ +*.pro.user + diff --git a/appl/refind/filefinder.cpp b/appl/refind/filefinder.cpp new file mode 100644 index 0000000..eb3e733 --- /dev/null +++ b/appl/refind/filefinder.cpp @@ -0,0 +1,204 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ + +#include "mainwindow.hpp" +#include "filefinder.hpp" + +FileFinder::FileFinder() : + m_lines(0), + m_patterns(), + m_minSize(0), + m_maxSize(-1), + m_youngerThan(), + m_olderThan(), + m_fileTypes(QDir::NoFilter), + m_minDepth(0), + m_maxDepth(512), + m_baseDir(""), + m_checkDates(false){ + m_youngerThan.setMSecsSinceEpoch(0); + m_olderThan.setMSecsSinceEpoch(0); +} + +/** + * Resets the data. + */ +void FileFinder::clear(){ + m_lines = 0; + m_patterns.clear(); + m_minSize = 0; + m_maxSize = -1; + m_youngerThan.setMSecsSinceEpoch(0); + m_olderThan.setMSecsSinceEpoch(0); + m_fileTypes = 0; + m_minDepth = 0; + m_maxDepth = 512; + // m_baseDir; + m_checkDates = false; +} + +/** + * Returns a string representation of the filesize. + * + * @param size the size to convert + * @return the filesize as a string + */ +QString fileSize(int64_t size){ + QString rc; + rc.sprintf("%.6f MB", (double) size / 1000000.0); + return rc; +} + +/** + * Fills the table with the data of the filtered files of a given directory. + * + * @param path the directory to inspect + * @param depth the depth of the directory (relative to base directory) + * @param table OUT: the table to fill + */ +void FileFinder::fillTable(const QString& path, int depth, QTableWidget* table){ + QDir dir(path); + QFileInfoList entries; + if (m_patterns.count() == 0) + entries = dir.entryInfoList(m_fileTypes, QDir::NoSort); + else + entries = dir.entryInfoList(m_patterns, m_fileTypes, QDir::NoSort); + QList ::iterator it; + QString relativePath = path.mid(1 + m_baseDir.length()); + for (it = entries.begin(); it != entries.end(); ++it){ + if (depth >= m_minDepth && isValid(*it)){ + if (m_lines >= table->rowCount()){ + table->setRowCount(m_lines + 500); + } + table->setItem(m_lines, TC_NODE, new QTableWidgetItem(it->fileName())); + table->setItem(m_lines, TC_PATH, new QTableWidgetItem(relativePath)); + QTableWidgetItem* item = new QTableWidgetItem(it->isDir() ? "dir" : fileSize(it->size())); + item->setTextAlignment(Qt::AlignRight); + table->setItem(m_lines, TC_SIZE,item); + table->setItem(m_lines, TC_MODIFIED, + new QTableWidgetItem( + it->lastModified().toString("yyyy.MM.dd hh:mm:ss"))); + m_lines++; + } + } + if (depth <= m_maxDepth){ + entries = dir.entryInfoList( + QDir::NoSymLinks | QDir::NoDotAndDotDot | QDir::AllDirs, QDir::NoSort); + for (it = entries.begin(); it != entries.end(); ++it){ + fillTable(path + QDir::separator() + it->fileName(), depth + 1, table); + } + } + table->setRowCount(m_lines); +} + +/** + * Tests whether a file matches the filter conditions. + * + * @param file the file to inspect + * @return true: the file matches the filter condition + */ +bool FileFinder::isValid(const QFileInfo& file){ + int64_t size = file.size(); + bool rc = size >= m_minSize && (m_maxSize < 0 || size <= m_maxSize); + bool checkYounger; + if (rc && ((checkYounger = m_youngerThan.toMSecsSinceEpoch() > 0) + || m_olderThan.toMSecsSinceEpoch() > 0)){ + QDateTime date = file.lastModified(); + rc = ! checkYounger || date >= m_youngerThan; + if (rc) + rc = m_olderThan.toMSecsSinceEpoch() == 0 || date <= m_olderThan; + } + return rc; +} + +/** + * Sets the base directory. + * + * @param baseDir the directory where the search starts + */ +void FileFinder::setBaseDir(const QString& baseDir){ + m_baseDir = baseDir; +} + +/** + * Sets the file types. + * + * @param filetypes the file types to set + */ +void FileFinder::setFiletypes(const QDir::Filters& filetypes){ + m_fileTypes = filetypes; +} + +/** + * Sets the maximum subdirectory depth. + * + * @param minDepth 0: search only in the base directory
+ * otherwise: the maximum depth + */ +void FileFinder::setMaxDepth(int maxDepth){ + m_maxDepth = maxDepth; +} +/** + * Sets the minimum subdirectory depth. + * + * @param minDepth 0: search in the base directory too
+ * otherwise: the minimum depth + */ +void FileFinder::setMinDepth(int minDepth){ + m_minDepth = minDepth; +} + +/** + * Sets the maximum size. + * + * @param maxSize the maximum size to set + */ +void FileFinder::setMaxSize(const int64_t& maxSize){ + m_maxSize = maxSize; +} + +/** + * Sets the minimum size. + * + * @param minSize the minimum size to set + */ +void FileFinder::setMinSize(const int64_t& minSize){ + m_minSize = minSize; +} + +/** + * Sets the date time which is the lower bound. + * + * @param olderThan the lower bound (including) + */ +void FileFinder::setOlderThan(const QDateTime& olderThan){ + m_olderThan = olderThan; + if (m_olderThan.toMSecsSinceEpoch() > 0) + m_checkDates = true; +} + +/** + * Sets the file patterns. + * + * @param patterns the patterns to set + */ +void FileFinder::setPatterns(const QStringList& patterns){ + m_patterns = patterns; +} + +/** + * Sets the date time which is the upper bound. + * + * @param youngerThan the upper bound (including) + */ +void FileFinder::setYoungerThan(const QDateTime& youngerThan){ + m_youngerThan = youngerThan; + if (youngerThan.toMSecsSinceEpoch() > 0) + m_checkDates = true; +} + diff --git a/appl/refind/filefinder.hpp b/appl/refind/filefinder.hpp new file mode 100644 index 0000000..6421c12 --- /dev/null +++ b/appl/refind/filefinder.hpp @@ -0,0 +1,48 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ + +#ifndef FILEFINDER_HPP +#define FILEFINDER_HPP +#include +#include +#include +#include + +class FileFinder { +public: + FileFinder(); +public: + void fillTable(const QString& path, int depth, QTableWidget* table); + void clear(); + void setBaseDir(const QString& baseDir); + void setFiletypes(const QDir::Filters& filetypes); + void setMaxDepth(int maxDepth); + void setMinDepth(int minDepth); + void setOlderThan(const QDateTime& olderThan); + void setPatterns(const QStringList& patterns); + void setMaxSize(const int64_t& maxSize); + void setMinSize(const int64_t& minSize); + void setYoungerThan(const QDateTime& youngerThan); + +private: + bool isValid(const QFileInfo& file); +private: + int m_lines; + QStringList m_patterns; + int64_t m_minSize; + int64_t m_maxSize; + QDateTime m_youngerThan; + QDateTime m_olderThan; + QDir::Filters m_fileTypes; + int m_minDepth; + int m_maxDepth; + QString m_baseDir; + bool m_checkDates; +}; + +#endif // FILEFINDER_HPP diff --git a/static/ReStaticLib.cpp b/appl/refind/main.cpp similarity index 59% rename from static/ReStaticLib.cpp rename to appl/refind/main.cpp index 487cb56..5117378 100644 --- a/static/ReStaticLib.cpp +++ b/appl/refind/main.cpp @@ -1,6 +1,6 @@ /* - * rplstaticlib.cpp - * + * main.cpp + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -10,7 +10,14 @@ */ -int main(int argc, char** argv){ - void allTests(); - allTests(); +#include "mainwindow.hpp" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); } diff --git a/appl/refind/mainwindow.cpp b/appl/refind/mainwindow.cpp new file mode 100644 index 0000000..12f4d3c --- /dev/null +++ b/appl/refind/mainwindow.cpp @@ -0,0 +1,189 @@ +/* + * mainwindow.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 +#include "base/rebase.hpp" +#include "mainwindow.hpp" +#include "ui_mainwindow.h" +#include "filefinder.hpp" + +/** + * @brief Constructor. + * + * @param parent NULL or the parent widget + */ +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow), + m_statusMessage(NULL), + m_stdLabelBackgroundRole(NULL), + m_errors(0) +{ + ui->setupUi(this); + m_statusMessage = new QLabel(tr("Willkommen bei refind")); + ui->comboBoxDirectory->setCurrentText(QDir::currentPath()); + statusBar()->addWidget(m_statusMessage); + connect(ui->pushButtonSearch, SIGNAL(clicked()), this, SLOT(search())); + connect(ui->pushButtonUp, SIGNAL(clicked()), this, SLOT(up())); + ui->tableWidget->setColumnWidth(TC_NODE, 200); + ui->tableWidget->setColumnWidth(TC_SIZE, 125); + ui->tableWidget->setColumnWidth(TC_MODIFIED, 175); + ui->tableWidget->horizontalHeader()->setStretchLastSection(true); +} + +/** + * @brief Destructor. + */ +MainWindow::~MainWindow() +{ + delete ui; +} +/** + * Returns the date given as formula in a combobox. + * + * @param combo the combobox with the date/time formula + * + * @return the date resulting from the formula or begin of the epoch (error case) + */ +QDateTime MainWindow::comboDate(QComboBox* combo){ + QDateTime rc; + QString value = combo->currentText(); + if (value.isEmpty()) + rc.setMSecsSinceEpoch(0); + else { + ReDateTimeParser parser(value); + if (parser.isValid()){ + rc.setMSecsSinceEpoch(QDateTime().addSecs(-parser.asInt64()).currentMSecsSinceEpoch()); + setInHistory(combo, value); + combo->setCurrentText(rc.toString("yyyy.MM.dd hh:mm")); + } else{ + guiError(combo, parser.errorMessage()); + rc.setMSecsSinceEpoch(0); + } + } + return rc; +} +/** + * Returns the size (in bytes) given as formula in a combobox. + * + * @param combo the combobox with the size formula + * + * @return -1: empty or invalid input
+ * otherwise: or the size resulting from the formula + */ +int64_t MainWindow::comboSize(QComboBox* combo){ + QString value = combo->currentText(); + int64_t rc = -1; + if (! value.isEmpty()){ + ReSizeParser parser(value); + int64_t rc = parser.asInt64(-1); + if (rc >= 0) + setInHistory(combo, value); + else + guiError(combo, parser.errorMessage()); + } + return rc; +} + +/** + * Handles an error found in an interactive widget. + * + * @param widget the widget where the error was found + * @param message the error message + */ +void MainWindow::guiError(QWidget* widget, const QString& message){ + widget->setFocus(Qt::OtherFocusReason); + setStatusMessage(true, message); + m_errors++; +} + +QString MainWindow::comboText(QComboBox* combo){ + QString rc = combo->currentText(); + setInHistory(combo, rc); + return rc; +} + + +/** + * Handles the "search" button. + */ +void MainWindow::search(){ + m_errors = 0; + QString path = ui->comboBoxDirectory->currentText(); + FileFinder finder; + finder.setBaseDir(path); + finder.setMaxSize(comboSize(ui->comboBoxMaxSize)); + finder.setMinSize(comboSize(ui->comboBoxMinSize)); + finder.setOlderThan(comboDate(ui->comboBoxOlder)); + finder.setYoungerThan(comboDate(ui->comboBoxYounger)); + QStringList patterns; + QString value = ui->comboBoxFilePatterns->currentText(); + if (! value.isEmpty()) + patterns = value.split(";"); + finder.setPatterns(patterns); + if (m_errors == 0) + finder.fillTable(path, 0, ui->tableWidget); + } + +/** + * @brief Sets a text in a combobox uses as history. + * + * Sets the text as the first entry. If the text can be found in other entries + * of the combobox it will be deleted there. + * + * @param combo the combobox to change + * @param value the text to set + */ +void MainWindow::setInHistory(QComboBox* combo, const QString& value){ + if (value.isEmpty()){ + // nothing to do + } else if (combo->count() == 0) + combo->addItem(value); + else { + if (value != combo->itemText(0)){ + combo->insertItem(0, value); + } + for (int ii = 1; ii < combo->count(); ii++){ + if (value == combo->itemText(ii)){ + combo->removeItem(ii); + } + } + if (combo->count() > 20) + combo->removeItem(20); + } +} + +/** + * Writes a text to the status line. + * + * @param error true: the message is an error message + * @param message the text to set + */ +void MainWindow::setStatusMessage(bool error, const QString& message){ + if (m_stdLabelBackgroundRole == NULL) + m_stdLabelBackgroundRole = new QPalette::ColorRole(m_statusMessage->backgroundRole()); + m_statusMessage->setBackgroundRole(error ? QPalette::HighlightedText : *m_stdLabelBackgroundRole); + m_statusMessage->setText(message); +} + +/** + * @brief Handles the "up" button: go to the parent directory. + */ +void MainWindow::up(){ + QString path = ui->comboBoxDirectory->currentText(); + int ix = path.lastIndexOf(QDir::separator()); + if (ix >= 0){ + path = path.mid(0, ix); + ui->comboBoxDirectory->setEditText(path); + setInHistory(ui->comboBoxDirectory, path); + } +} diff --git a/appl/refind/mainwindow.hpp b/appl/refind/mainwindow.hpp new file mode 100644 index 0000000..c509944 --- /dev/null +++ b/appl/refind/mainwindow.hpp @@ -0,0 +1,54 @@ +/* + * mainwindow.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 MAINWINDOW_HPP +#define MAINWINDOW_HPP + +#include +#include +#include + + +namespace Ui { +class MainWindow; +} +enum TableColumns { + TC_NODE, TC_SIZE, TC_MODIFIED, TC_PATH +}; + +class MainWindow : public QMainWindow +{ + + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void search(); + void up(); +private: + QDateTime comboDate(QComboBox* combo); + int64_t comboSize(QComboBox* combo); + QString comboText(QComboBox* combo); + void guiError(QWidget* widget, const QString& message); + void setInHistory(QComboBox* combo, const QString& value); + void setStatusMessage(bool error, const QString& message); +private: + Ui::MainWindow *ui; + QLabel* m_statusMessage; + QPalette::ColorRole* m_stdLabelBackgroundRole; + int m_errors; +}; + +#endif // MAINWINDOW_HPP diff --git a/appl/refind/mainwindow.ui b/appl/refind/mainwindow.ui new file mode 100644 index 0000000..508205f --- /dev/null +++ b/appl/refind/mainwindow.ui @@ -0,0 +1,429 @@ + + + MainWindow + + + + 0 + 0 + 1134 + 579 + + + + MainWindow + + + + + + + + + + + + + true + + + + + + + + 200 + 16777215 + + + + File Patterns: + + + + + + + + 200 + 16777215 + + + + Text Pattern: + + + + + + + + 300 + 0 + + + + true + + + + + + + + + + 50 + 16777215 + + + + Up + + + + + + + + 50 + 16777215 + + + + ... + + + + + + + + + Search + + + Ctrl+F + + + + + + + ignore case + + + + + + + + 200 + 16777215 + + + + Directory: + + + + + + + + 200 + 16777215 + + + + true + + + + + + + + 200 + 16777215 + + + + true + + + + + + + + 200 + 16777215 + + + + Younger than: + + + + + + + + 150 + 16777215 + + + + Min. Size: + + + + + + + + 150 + 16777215 + + + + Max Size + + + + + + + + 200 + 16777215 + + + + true + + + + + + + + 200 + 16777215 + + + + true + + + + + + + + 200 + 16777215 + + + + Older than: + + + + + + + true + + + + + + + + + + + + Filename + + + + + Size + + + AlignRight|AlignVCenter + + + + + Modified + + + + + Path + + + + + + + + + + Files: + + + + + + + + 100 + 16777215 + + + + + + + + Size: + + + + + + + + 100 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 0 + 0 + 1134 + 23 + + + + + File + + + + + + + + + + + Help + + + + + + + + + TopToolBarArea + + + false + + + + + + Exit + + + Exits the program + + + Ctrl+X + + + + + Search + + + Search the files with the given properties + + + Ctrl+F + + + + + About + + + Informs about the author + + + Space + + + + + About + + + + + Export + + + + + + + + actionExit + triggered() + MainWindow + close() + + + -1 + -1 + + + 566 + 289 + + + + + diff --git a/appl/refind/refind.pro b/appl/refind/refind.pro new file mode 100644 index 0000000..e1776c0 --- /dev/null +++ b/appl/refind/refind.pro @@ -0,0 +1,30 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2015-04-02T23:48:19 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = refind +TEMPLATE = app + +INCLUDEPATH = ../.. /usr/include/c++/4.9 + +SOURCES += main.cpp\ + mainwindow.cpp \ + ../../base/ReException.cpp \ + ../../base/ReQStringUtil.cpp \ + ../../base/ReLogger.cpp \ + filefinder.cpp + + +HEADERS += mainwindow.hpp \ + ../../base/rebase.hpp \ + filefinder.hpp \ + ../../base/ReQStringUtil.hpp + + +FORMS += mainwindow.ui diff --git a/base/ReByteStorage.cpp b/base/ReByteStorage.cpp deleted file mode 100644 index 644c7c2..0000000 --- a/base/ReByteStorage.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * ReByteStorage.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 A very efficient storage for bytes and C strings. - */ -/** @file rplcore/rplbytestorage.hpp - * - * @brief Definitions for a very efficient storage for bytes and C strings. - */ - -#include "base/rebase.hpp" -/** @class ReByteStorage ReByteStorage.hpp "base/ReByteStorage.hpp" - * - * @brief Implements a very efficient byte storage. - * - * Efficiency: Allocation of one block needs mostly only 1 comparison - * and 2 assignments. - * - * Restriction: The blocks can be returned (freed) only all together, not block by block. - * This can be an advantage! - * - * Process: - * The storage manages large buffers. Allocation can be done only in the - * last buffer. If the buffer has too little space for the new block a new - * buffer will be allocated and linked into the buffer list. - * One buffer can store dozens or hundreds of blocks. Therefore allocation and - * freeing is much cheeper than allocation by new(). - */ - -/** - * @brief Constructor. - * - * @param bufferSize the size of one buffer - */ -ReByteStorage::ReByteStorage(int bufferSize) : - m_bufferSize(bufferSize), - m_buffer(NULL), - m_rest(0), - m_freePosition(NULL), - m_summarySize(0), - m_buffers(0){ -} - -/** - * @brief Destructor. - */ -ReByteStorage::~ReByteStorage(){ - const uint8_t* ptr = m_buffer; - while (ptr != NULL){ - const uint8_t* old = ptr; - ptr = *(const uint8_t**) (ptr); - delete[] old; - m_buffers--; - } - assert(m_buffers == 0); -} - -/** - * @brief Allocates a block in a new allocated buffer. - * - * This method will be called if the buffer has too little space. - * A new buffer will be allocated and the block will be allocated - * in this new block. - * - * @note The block address is returned, but the allocation must be done outside! - * - * @param size of the new block (inclusive the trailing '\0') - * @return a new block with the size bytes - */ -char* ReByteStorage::allocBuffer(int size){ - m_rest = size + sizeof(uint8_t*) <= (size_t) m_bufferSize ? - m_bufferSize : size + sizeof(uint8_t*); - m_summarySize += m_rest; - m_buffers++; - uint8_t* rc = new uint8_t[m_rest]; - *(uint8_t**) rc = m_buffer; - m_buffer = rc; - rc += sizeof(uint8_t*); - // the block allocation will be done outside! - m_freePosition = rc; - m_rest -= sizeof(uint8_t*); - return reinterpret_cast (rc); -} - -/** - * @brief Duplicates a string into a new allocated block. - * - * @param source the source string - * @param size the length of the string. - * If < 0 strlen(source) will be used - * @return a copy of the source string. The copy ends always with '\0' - */ -const char* ReByteStorage::allocateChars(const char* source, int size){ - if (size < 0) - size = strlen(source); - const char* rc = allocateChars(size + 1); - memcpy((void*) rc, source, size); - ((char*) rc)[size] = '\0'; - return rc; -} - -/** - * @brief Duplicates a string into a new allocated block. - * - * The unicode string will be converted into an UTF-8 string. - * - * @param source the source string - * @return a copy of the source string. The copy ends always with '\0' - */ -const char* ReByteStorage::allocUtf8(const ReString& source){ - const char* rc = allocateChars(source.toUtf8().constData()); - return rc; -} - -/** - * @brief Allocates a byte block without initialization. - * - * @param size the size of the block to allocate - * - * @return a byte block (without a trailing '\0') - */ -uint8_t* ReByteStorage::allocateBytes(int size){ - uint8_t* rc = - size <= m_rest ? - m_freePosition : reinterpret_cast (allocBuffer(size)); - m_freePosition += size; - m_rest -= size; - return rc; -} - -/** - * @brief Allocates a byte block initialized by '\0'. - * - * @param size the size of the block to allocate - * - * @return a byte block (without a trailing '\0') - */ -uint8_t* ReByteStorage::allocateZeros(int size){ - uint8_t* rc = allocateBytes(size); - memset(rc, 0, size); - return rc; -} - -/** - * @brief Copy a byte block to a new allocated byte block. - * - * @param source the source to copy - * @param size the size of the block to allocate - * @return a byte block (without a trailing '\0') - */ -uint8_t* ReByteStorage::allocateBytes(void* source, int size){ - uint8_t* rc = allocateBytes(size); - memcpy(rc, source, size); - return rc; -} diff --git a/base/ReByteStorage.hpp b/base/ReByteStorage.hpp deleted file mode 100644 index e54fb96..0000000 --- a/base/ReByteStorage.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ReByteStorage.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 RECHARSTORAGE_HPP -#define RECHARSTORAGE_HPP - -class ReByteStorage { -public: - ReByteStorage(int blockSize); - ~ReByteStorage(); -public: - char* allocBuffer(int size); - /** - * @brief Allocates a char block. - * - * @return a new block - */ - inline char* allocateChars(int size){ - char* rc = size <= m_rest ? (char*) m_freePosition : allocBuffer(size); - m_freePosition += size; - m_rest -= size; - return rc; - } - const char* allocateChars(const char* source, int size = -1); - const char* allocUtf8(const ReString& source); - uint8_t* allocateBytes(int size); - uint8_t* allocateZeros(int size); - uint8_t*allocateBytes(void* source, int size); -private: - int m_bufferSize; - uint8_t* m_buffer; - int m_rest; - uint8_t* m_freePosition; - int64_t m_summarySize; - int m_buffers; -}; - -#endif // RECHARSTORAGE_HPP diff --git a/base/ReCharPtrMap.cpp b/base/ReCharPtrMap.cpp deleted file mode 100644 index c898af5..0000000 --- a/base/ReCharPtrMap.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ReCharPtrMap.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 ReKeyCharPtr ReCharPtrMap.hpp "base/ReCharPtrMap.hpp" - * - * @brief Allows using char* pointers as key in QMap. - * - * The template QMap uses the operator < to search in the map. - * But the char* pointers have no such an operator. - * The solution is the class RplMapCharPtr which implements - * this operator. - * - * strcmp() is used to implement the '<' operator. - */ - -/** - * @brief Constructor. - * - * @param ptr the key used in the map. - * @note the pointer will be stored in the map as a key, - * not the content - */ -ReKeyCharPtr::ReKeyCharPtr(const char* ptr) : - m_ptr(ptr){ -} - -/** @class ReCharPtrMap ReCharPtrMap.hpp "base/ReCharPtrMap.hpp" - * - * @brief A template for a map using const char* as keys. - * - * The value type is dynamic (a parameter type of the template). - * - * Usage: - *

- * ReCharPtrMap ids;
- * if (! id.contains("jonny"))
- *    ids["jonny"] = 1;
- * 
- * - * Important:
- * Keys used with this class must be unchangable and must live during the - * whole life of the map. - * - * Wrong example: - *

- * ReCharPtrMap ids;
- * void init(int keyNo, int value){
- *    char key[10];
- *    qsnprintf(buffer, sizeof buffer, "key%d", keyNo);
- *    ids[key] = value;
- * }
- * init(1, 100);
- * 
- * The lifetime of the key is the body of the function init(). - * The key becomes invalid after the call. - */ diff --git a/base/ReCharPtrMap.hpp b/base/ReCharPtrMap.hpp deleted file mode 100644 index 6a7b515..0000000 --- a/base/ReCharPtrMap.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ReCharPtrMap.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 RECHARPTRMAP_HPP -#define RECHARPTRMAP_HPP - -class ReKeyCharPtr { - friend bool operator <(ReKeyCharPtr const& op1, ReKeyCharPtr const& op2); -public: - ReKeyCharPtr(const char* ptr); -private: - const char* m_ptr; -}; -/** - * @brief Compares two instances of the class ReKeyCharPtr. - * @param op1 1st operand - * @param op2 2nd operand - * @return true: op1 < op2
- * false: op1 >= op2 - */ -inline bool operator <(ReKeyCharPtr const& op1, ReKeyCharPtr const& op2){ - bool rc = strcmp(op1.m_ptr, op2.m_ptr) < 0; - return rc; -} - -template -class ReCharPtrMap: public QMap { -}; - -#endif // RECHARPTRMAP_HPP diff --git a/base/ReConfig.cpp b/base/ReConfig.cpp deleted file mode 100644 index 9962b2b..0000000 --- a/base/ReConfig.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * ReConfig.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 Reading/writing configuration files. - */ -/** @file rplcore/rplconfig.hpp - * - * @brief Definitions for reading/writing configuration files. - */ - -/** @class ReConfig ReConfig.hpp "base/ReConfig.hpp" - * - * @brief Imports and exports a configuration file into a QHash instance. - * - * The format of the file:
- * DEFS or COMMENTS - * - * DEFS ::= KEY=VALUE - * - * KEY is a string starting with an alphanumeric character and does not contain a '=' - * - * VALUE is a string - */ - -enum Locations { - LOC_WRITE_1 = LOC_FIRST_OF(LOC_CONFIG), // 10201 - LOC_WRITE_2, LOC_READ_1, LOC_READ_2, -}; - -/** - * Constructor. - * - * Initializes the logger and reads the configuration file - * - * @param file name of the configuration file. May be NULL - * @param readOnly true: the configuration must not be written - * @param logger NULL or a logger - */ -ReConfig::ReConfig(const char* file, bool readOnly, ReLogger* logger) : - m_file(file), - m_lineList(), - m_readOnly(readOnly), - m_logger(logger), - m_ownLogger(logger == NULL){ - if (logger == NULL){ - initLogger(); - } - if (file != NULL) - read(file); -} - -/** - * Destructor. - * - * Frees the resources. - */ -ReConfig::~ReConfig(){ - if (m_ownLogger) - delete m_logger; - m_logger = NULL; -} - -/** - * Inititializes a logger. - */ -void ReConfig::initLogger(){ - m_logger = new ReLogger(); - ReMemoryAppender* appender = new ReMemoryAppender(); - appender->setAutoDelete(true); - m_logger->addAppender(appender); - - ReStreamAppender* appender2 = new ReStreamAppender(stdout); - appender2->setAutoDelete(true); - m_logger->addAppender(appender2); -} - -/** - * Returns configuration value as an integer. - * - * @param key key of the wanted value - * @param defaultValue if the key does not exist this is the result - * @return defaultValue: key does not exist - * otherwise: the value assigned to key - */ -int ReConfig::asInt(const char* key, int defaultValue) const{ - int rc = defaultValue; - if (contains(key)){ - rc = atoi((*this)[key]); - } - return rc; -} - -/** - * Returns the configuration value as a boolean. - * - * @param key key of the wanted value - * @param defaultValue if the key does not exist this is the result - * @return defaultValue: key does not exist - * otherwise: the value assigned to key - */ -bool ReConfig::asBool(const char* key, bool defaultValue) const{ - bool rc = defaultValue; - if (contains(key)){ - QByteArray value = (*this)[key].toLower(); - rc = value == "1" || value == "y" || value == "yes" || value == "t" - || value == "true"; - } - - return rc; -} - -/** - * Returns a configuration value. - * - * @param key key of the wanted value - * @param defaultValue if the key does not exist this is the result - * @return defaultValue: key does not exist - */ -QByteArray ReConfig::asString(const char* key, const char* defaultValue){ - QByteArray rc = defaultValue; - if (contains(key)){ - rc = (*this)[key]; - } - return rc; -} - -/** - * Reads a configuration file. - * - * @param file file to read. - * @return true: OK
- * false: error occurred - */ -bool ReConfig::read(const char* file){ - bool rc = true; - m_lineList.reserve(1024); - FILE* fp = fopen(file, "r"); - if (fp == NULL){ - m_logger->logv(LOG_ERROR, LOC_READ_1, "cannot read: %s", file); - rc = false; - }else{ - char line[64000]; - char* separator; - int lineNo = 0; - while (fgets(line, sizeof line, fp) != NULL){ - lineNo++; - m_lineList.append(line); - if (isalnum(line[0]) && (separator = strchr(line, '=')) != NULL){ - QByteArray key(line, separator - line); - QByteArray value(separator + 1); - key = key.trimmed(); - value = value.trimmed(); - if (contains(key)) - m_logger->logv(LOG_WARNING, LOC_READ_2, - "defined more than once: %s-%d: %s", file, lineNo, line); - else - insert(key, value); - } - } - } - return rc; -} - -/** - * Writes a configuration file. - * - * @param file file to write. - * @return true: OK
- * false: error occurred - */ -bool ReConfig::write(const char* file){ - bool rc = false; - if (m_readOnly) - m_logger->log(LOG_ERROR, LOC_WRITE_1, "cannot write: (readonly"); - else{ - m_logger->logv(LOG_ERROR, LOC_WRITE_2, "not implemented: write(%s)", - file); - } - return rc; -} - diff --git a/base/ReConfig.hpp b/base/ReConfig.hpp deleted file mode 100644 index d022162..0000000 --- a/base/ReConfig.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ReConfig.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 RECONFIG_HPP -#define RECONFIG_HPP - -class ReConfig: public ReConfigurator, public QHash { -public: - ReConfig(const char* file = NULL, bool readOnly = true, ReLogger* logger = - NULL); - virtual ~ReConfig(); - -public: - bool read(const char* file); - bool write(const char* file); - void clear(); - const QList & getLines() const; - - virtual bool asBool(const char* key, bool defaultValue) const; - virtual int asInt(const char* key, int defaultValue) const; - virtual QByteArray asString(const char* key, const char* defaultValue); -private: - void initLogger(); -private: - const char* m_file; - QList m_lineList; - bool m_readOnly; - ReLogger* m_logger; - // true: the logger must be destroyed in the destructor - bool m_ownLogger; -}; - -#endif // RECONFIG_HPP diff --git a/base/ReConfigurator.hpp b/base/ReConfigurator.hpp deleted file mode 100644 index 49adc42..0000000 --- a/base/ReConfigurator.hpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ReConfigurator.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 RECONFIGURATOR_HPP -#define RECONFIGURATOR_HPP - -class ReConfigurator { -public: - virtual int asInt(const char* key, int defaultValue) const = 0; - virtual bool asBool(const char* key, bool defaultValue) const = 0; - virtual QByteArray asString(const char* key, const char* defaultValue) = 0; -}; - -#endif // RECONFIGURATOR_HPP diff --git a/base/ReContainer.cpp b/base/ReContainer.cpp deleted file mode 100644 index 67a439a..0000000 --- a/base/ReContainer.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/* - * ReContainer.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 Implements a portable data container. - */ - -/** @file recore/ReContainer.hpp - * - * @brief Definition for a portable data container. - */ - -/** @class ReContainer ReContainer.hpp "base/ReContainer.hpp" - * - * @brief Implements a portable data container. - * - * The container contains a list of "bags". - * Each bag contains a sequence of items (with a simple data type). - * The items are portable: transported to another architecture - * the item is restored correct (independent of big/little endian). - * - * Format: - * container ::= magic header_size_hex2 container_size_hex '[' list_count ']' bag_descr list_of_bags
- * list_of_bag ::= bag1 bag2 ...
- * bag_descr ::= bag_type1 bag_type2 ... ':'
- * bag_types := i(nteger) ' ' | s(tring) | b(indata255) | B(indata64k) X(blob4G)
- * item_list ::= item1 item2...
- * The binary items (bBX) are byte sequences with a starting size element. - * The size element can be a byte (255) or a word (64k) or a double word(4G). - * The order of the size element is big endian. - * - * Example (additional blanks for readibility): - *
- * Rpl&1 09 36[2]cis:!7b Nirwana <0> Y -ab34 A long string with an trailing '0' <0>
- * 
- * magic header: Rpl&1 length: 09h data length: 46h bag count: 2 item types: char int string - * - */ - -enum { - // 11000 - LOC_FILL_1 = LOC_CONTAINER * 1000, - LOC_FILL_2, - LOC_FILL_3, - LOC_NEXT_BAG_1, - LOC_NEXT_ITEM_1, - LOC_NEXT_ITEM_2 = 11005, - LOC_NEXT_INT_1, - LOC_NEXT_ITEM_3, - LOC_NEXT_BAG_2, -}; - -const char* ReContainer::MAGIC_1 = "Rpl&1"; - -/** - * @brief Constructor. - * - * @param sizeHint Probable length of the container - */ -ReContainer::ReContainer(size_t sizeHint) : - m_data(""), - m_countBags(0), - m_typeList(""), - m_ixItem(0), - m_ixBag(0), - m_readPosition(NULL){ - if (sizeHint > 0) - m_data.reserve(sizeHint); -} - -/** - * @brief Destructor. - */ -ReContainer::~ReContainer(){ -} - -/** - * @brief Adds an type to the type list. - * - * @param tag the type tag - */ -void ReContainer::addType(type_tag_t tag){ - if (m_countBags == 0) - startBag(); - if (m_countBags == 1) - m_typeList.append((char) tag); -} - -/** - * @brief Starts a new bag. - */ -void ReContainer::startBag(){ - m_countBags++; - m_ixBag = 0; -} -/** - * @brief Adds a character to the current bag. - * - * @param value value to insert - */ -void ReContainer::addChar(char value){ - addType(TAG_CHAR); - //if (m_typeList.at(m_ixBag) != TAG_INT) - // ReLogger::logAndThrow(LOG_ERROR, __FILE__, __LINE__, 1, "unexpected type: %c instead of c", m_typeList.at(m_ixBag)); - m_data.append(value); -} -/** - * @brief Adds an integer to the current bag. - * - * @param value value to add - */ -void ReContainer::addInt(int value){ - addType(TAG_INT); - char buffer[64]; - char* ptr = buffer; - if (value < 0){ - *ptr++ = '-'; - value = -value; - } - qsnprintf(ptr, sizeof buffer - 1, "%x ", value); - m_data.append(buffer); -} -/** - * @brief Adds an integer to the current bag. - * - * @param value value to add - */ -void ReContainer::addInt(int64_t value){ - addType(TAG_INT); - char buffer[128]; - qsnprintf(buffer, sizeof buffer, "%llx ", value); - m_data.append(buffer); -} - -/** - * @brief Adds a string to the current bag.n - * - * @param value value to add - */ -void ReContainer::addString(const char* value){ - addType(TAG_STRING); - // store with trailing '\0' - m_data.append(value, strlen(value) + 1); -} -/** - * @brief Adds binary data to the current bag. - * - * @param value binary data - * @param size size of the binary data in bytes - */ -void ReContainer::addData(uint8_t* value, size_t size){ - if (size <= 255){ - addType(TAG_DATA255); - m_data.append((char) size); - }else if (size <= 0xffff){ - addType(TAG_DATA64K); - m_data.append((char) (size / 256)); - m_data.append((char) (size % 256)); - m_data.append((const char*) value, size); - }else{ - addType(TAG_DATA4G); - m_data.append((char) (size / 256 / 256 / 256)); - m_data.append((char) (size / 256 / 256 % 256)); - m_data.append((char) (size / 256 % 256)); - m_data.append((char) (size % 256)); - m_data.append((const char*) value, size); - } - addType(TAG_DATA255); - -} - -/** - * @brief Returns the container byte buffer. - * - * @return the container as a byte array - */ -const QByteArray& ReContainer::getData(){ - if (m_typeList.length() != 0){ - char buffer[128]; - // RPL&1 0a b5[2]cis: !12 - qsnprintf(buffer, sizeof buffer, "%x[%d]%s:", - (unsigned int) m_data.length(), m_countBags, m_typeList.data()); - char header[128 + 8]; - qsnprintf(header, sizeof header, "%s%02x%s", MAGIC_1, - (unsigned int) strlen(buffer), buffer); - m_data.insert(0, header); - } - return m_data; -} - -/** - * @brief Fills the container with an byte array. - * - * @param data the container as a byte array - */ -void ReContainer::fill(const QByteArray& data){ - m_data = data; - const char* ptr = m_data.data(); - if (strncmp(ptr, MAGIC_1, strlen(MAGIC_1)) != 0) - throw RplInvalidDataException(LOG_ERROR, LOC_FILL_1, - "container has no magic", data.data(), data.length()); - ptr += strlen(MAGIC_1); - unsigned int headerSize = 0; - if (sscanf(ptr, "%02x", &headerSize) != 1) - throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2, - "container has no header size", ptr, 2); - ptr += 2; - - unsigned int dataSize = 0; - unsigned int countBags = 0; - if (sscanf(ptr, "%x[%x]", &dataSize, &countBags) != 2) - throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2, - "container has no data_size[bag_count]", ptr, 16); - m_countBags = countBags; - ptr = strchr(ptr, ']') + 1; - const char* end = ptr + strspn(ptr, "cisdDX!"); - if (end == ptr || *end != ':'){ - throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2, - "container has no valid typelist", ptr, 16); - } - m_typeList.clear(); - m_typeList.append(ptr, end - ptr); - m_ixBag = -1; - m_readPosition = (uint8_t*) end + 1; - -} -/** - * @brief Returns the number of bags in the container. - * - * @return the number of bags - */ -int ReContainer::getCountBags() const{ - return m_countBags; -} -/** - * @brief Sets the begin of the new bag. - */ -void ReContainer::nextBag(){ - if (m_ixItem < m_typeList.length() && m_ixItem != -1) - throw ReException(LOG_ERROR, LOC_NEXT_BAG_1, NULL, - "end of bag not reached: remaining items: %s", - m_typeList.data() + m_ixItem); - m_ixItem = 0; - m_ixBag++; - if (m_ixBag >= m_countBags) - throw ReException(LOG_ERROR, LOC_NEXT_BAG_2, NULL, "no more bags: %d", - m_ixBag); -} -/** - * @brief Sets the next item. - * - * @param expected the expected data type - */ -void ReContainer::nextItem(type_tag_t expected){ - if (m_ixBag < 0){ - m_ixBag = 0; - m_ixItem = 0; - } - if (m_ixItem >= m_typeList.length()) - 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) - current = TAG_DATA255; - if (current != expected) - throw ReException(LOG_ERROR, LOC_NEXT_ITEM_2, NULL, - "current item is a %c, not a %c", (char) m_typeList.at(m_ixItem), - (char) expected); - m_ixItem++; - if (m_readPosition > (uint8_t*) (m_data.data() + m_data.length())) - throw ReException(LOG_ERROR, LOC_NEXT_ITEM_3, NULL, - "container size too small. Bag: %d of %d Item: %d of %d", 1 + m_ixBag, - m_countBags, 1 + m_ixItem, m_typeList.length()); -} - -/** - * @brief Reads the next character from the current item in the current bag. - * - * @return the next char from the container - */ -char ReContainer::nextChar(){ - nextItem(TAG_CHAR); - char rc = *m_readPosition++; - return rc; -} - -/** - * @brief Reads the next integer from the current item in the current bag. - * - * @return the next integer from the container - */ -int ReContainer::nextInt(){ - nextItem(TAG_INT); - bool isNegativ = *m_readPosition == '-'; - if (isNegativ) - m_readPosition++; - unsigned int value = 0; - if (sscanf((const char*) m_readPosition, "%x ", &value) != 1) - throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1, - "not a hex_number", m_readPosition, 16); - m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1; - if (isNegativ) - value = -value; - return value; -} -/** - * @brief Reads the next integer from the current item in the current bag. - * - * @return the next integer from the container - */ -int64_t ReContainer::nextInt64(){ - nextItem(TAG_INT); - bool isNegativ = *m_readPosition == '-'; - if (isNegativ) - m_readPosition++; - uint64_t value = 0; - if (sscanf((const char*) m_readPosition, "%llx ", &value) != 1) - throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1, - "not a hex_number", m_readPosition, 16); - m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1; - if (isNegativ) - value = -value; - return (int64_t) value; -} - -/** - * @brief Reads the next string from the current item in the current bag. - * - * @return the next '\0' delimited string from the container - */ -const char* ReContainer::nextString(){ - nextItem(TAG_STRING); - const char* rc = (const char*) m_readPosition; - m_readPosition += strlen(rc) + 1; - return rc; -} - -/** - * @brief Reads the next string from the current item in the current bag. - * - * @param data OUT: the next data item from the container - * @param append true: the item data will be appended to data
- * false: data contains the item data only - * @return the size of the read data - */ -size_t ReContainer::nextData(QByteArray& data, bool append){ - nextItem(TAG_DATA255); - type_tag_t tag = (type_tag_t) m_typeList.at(m_ixItem - 1); - size_t length = 0; - switch (tag) { - case TAG_DATA4G: - for (int ix = 3; ix >= 0; ix--){ - length = 256 * length + m_readPosition[ix]; - } - m_readPosition += 4; - break; - case TAG_DATA64K: - length = *m_readPosition++ * 256; - length += *m_readPosition++; - break; - case TAG_DATA255: - length = *m_readPosition++; - break; - default: - break; - } - if (!append) - data.clear(); - data.append((const char*) m_readPosition, length); - m_readPosition += length; - return length; -} - -/** - * @brief Dumps a container as a human readable string. - * - * @param title will be used in the first line - * @param maxBags if there are more bags they will be ignored - * @param maxStringLength if strings are longer the will be cut - * @param maxBlobLength maximum count of bytes which will be dumped - * @param separatorItems separator between two items, e.g. '\\n' or '|' - * @return a human readable string describing the container - */ -QByteArray ReContainer::dump(const char* title, int maxBags, - int maxStringLength, int maxBlobLength, char separatorItems){ - QByteArray rc; - rc.reserve(64000); - rc.append("=== ").append(title).append('\n'); - rc.append("Bags: ").append(ReStringUtil::toNumber(m_countBags)); - rc.append(" Types: ").append(m_typeList).append('\n'); - // save the current state: - int safeIxBag = m_ixBag; - int safeIxItem = m_ixItem; - m_ixBag = -1; - m_ixItem = 0; - int iValue; - QByteArray sValue; - if (maxBags > m_countBags) - maxBags = m_countBags; - for (int ixBag = 0; ixBag < maxBags; ixBag++){ - rc.append("--- bag ").append(ReStringUtil::toNumber(ixBag)).append(":\n"); - nextBag(); - QByteArray item; - int maxLength; - for (int ixItem = 0; ixItem < m_typeList.length(); ixItem++){ - type_tag_t currentType = (type_tag_t) m_typeList.at(ixItem); - switch (currentType) { - case TAG_CHAR: - rc.append(" c: ").append(nextChar()).append(separatorItems); - break; - case TAG_INT: - iValue = nextInt(); - rc.append(" i: ").append(ReStringUtil::toNumber(iValue)).append( - " / "); - rc.append(ReStringUtil::toNumber(iValue, "%x")).append( - separatorItems); - break; - case TAG_STRING: - sValue = nextString(); - if (sValue.length() > maxStringLength) - sValue = sValue.left(maxStringLength); - rc.append(" s: ").append(sValue).append(separatorItems); - break; - case TAG_DATA255: - case TAG_DATA64K: - case TAG_DATA4G: - nextData(item, false); - rc.append(' ').append((char) currentType).append(": ["); - rc.append(ReStringUtil::toNumber(item.length())).append("] "); - maxLength = - item.length() < maxBlobLength ? - item.length() : maxBlobLength; - rc.append(ReStringUtil::hexDump(item.data(), maxLength, 16)).append( - separatorItems); - break; - default: - break; - } - } - } - - // restore the current state: - m_ixBag = safeIxBag; - m_ixItem = safeIxItem; - return rc; -} - diff --git a/base/ReContainer.hpp b/base/ReContainer.hpp deleted file mode 100644 index 8d1dcc2..0000000 --- a/base/ReContainer.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ReContainer.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 RECONTAINER_HPP -#define RECONTAINER_HPP - -// the sources generated from QT include this file directly: -#ifndef RPLCORE_HPP -#include -#include -#endif -class ReContainer { -public: - typedef enum { - - TAG_CHAR = 'c', ///< one character - TAG_INT = 'i', ///< an integer number, up to 64 bit - TAG_STRING = 's', ///< a string ending with a '\\0' - TAG_DATA255 = 'd', ///< binary data, up to 255 bytes long - TAG_DATA64K = 'D', ///< binary data, up to 64 KiBytes long - TAG_DATA4G = 'X', ///< binary data, up to 4 GiBytes long - TAG_CONTAINER = '!' ///< a container (recursion) - } type_tag_t; - static const char* MAGIC_1; -public: - ReContainer(size_t sizeHint); - virtual ~ReContainer(); -private: - // No copy constructor: no implementation! - ReContainer(const ReContainer& source); - // Prohibits assignment operator: no implementation! - ReContainer& operator =(const ReContainer& source); -public: - // Building the container: - void addType(type_tag_t tag); - void startBag(); - void addChar(char cc); - void addInt(int value); - void addInt(int64_t value); - void addString(const char* value); - void addData(uint8_t* value, size_t size); - const QByteArray& getData(); - - // Getting data from the container: - void fill(const QByteArray& data); - int getCountBags() const; - const char* getTypeList() const; - void nextBag(); - char nextChar(); - int nextInt(); - int64_t nextInt64(); - const char* nextString(); - size_t nextData(QByteArray& data, bool append = false); - - QByteArray dump(const char* title, int maxBags, int maxStringLength = 80, - int maxBlobLength = 16, char separatorItems = '\n'); -private: - void nextItem(type_tag_t expected); -private: - // the complete data of the container - QByteArray m_data; - // the number of elements in the container - int m_countBags; - // a string with the data types of a bag - QByteArray m_typeList; - - // Getting data from the container: - - // current read position in m_typeList - int m_ixItem; - // the index of the current current bag: - int m_ixBag; - // read position in m_data: - const uint8_t* m_readPosition; -}; - -#endif // RECONTAINER_HPP diff --git a/base/ReException.cpp b/base/ReException.cpp deleted file mode 100644 index 024acbd..0000000 --- a/base/ReException.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* - * ReException.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 - */ -/** @mainpage - * - * @note A real public library for QT. - * - * This library contains the module groups - *
    - *
  • rplcore: basic definitions, used in all other module groups
  • - *
  • rplmath: mathematic definitions and tools
  • - *
  • rplexpr: definition for parsing and interpretation of languages
  • - *
  • rplnet: definitions and tools for tcp/udp communication
  • - *
- * - * Each module group has a central include file, which organizes the necessary - * include files. You had to include only the central include file. - * - * Example: - *

- * #include "base/rebase.hpp"
- * #include "expr/reexpr.hpp"
- * 
- * In this case all definitions of rplcore and rplexpr are available. - */ -/** @file - * @brief Generally usable exceptions. - */ -/** @file rplcore/rplexception.hpp - * - * @brief Definitions for a generally usable exceptions. - */ -#include "base/rebase.hpp" - -enum { - LOC_NOT_IMPLEMENTED_1 = LOC_FIRST_OF(LOC_EXCEPTION), -}; -/** @class ReException ReException.hpp "base/ReException.hpp" - * - * @brief A generally usable exception with or without logging. - * - * Note: If the logger is not given by parameter - * the usage of the global logger is not threadsafe. - */ -class ReException; - -/** - * @brief Constructor. - * - * For derived classes only! - */ -ReException::ReException() : - m_message(""){ -} - -/** - * @brief Constructor. - * - * @param format the reason of the exception - * @param ... the values for the placeholders in the format. - */ -ReException::ReException(const char* format, ...) : - m_message(""){ - char buffer[64000]; - va_list ap; - va_start(ap, format); - qvsnprintf(buffer, sizeof buffer, format, ap); - va_end(ap); - m_message = buffer; -} - -/** - * @brief Constructor. - * - * This constructor automatically logs the given data. - * - * @param level the logging level, e.g. LOG_ERROR - * @param location an unique identifier for the location - * where the exception was thrown - * @param format the reason of the exception. - * Can contain placeholders (@see - * std::printf()) - * @param ... the values of the placeholders - * in format - * @param logger if NULL the global logger will be used - */ -ReException::ReException(ReLoggerLevel level, int location, ReLogger* logger, - const char* format, ...) : - m_message(""){ - char buffer[64000]; - va_list ap; - va_start(ap, format); - qvsnprintf(buffer, sizeof buffer, format, ap); - va_end(ap); - m_message = buffer; - if (logger == NULL) - logger = ReLogger::globalLogger(); - logger->log(level, location, buffer); -} - -/** @class RplRangeException rplexception.hpp "rplcore/rplexception.hpp" - * - * @brief An exception for integer range errors. - * - * The error will be logged. - * - * Note: If the logger is not given by parameter - * the usage of the global logger is not threadsafe. - */ - -/** - * @brief Constructor. - * - * This exception can be used if a value does not be - * inside a given range. - * - * This constructor automatically logs the given data. - * - * @param level the logging level, e.g. LOG_ERROR - * @param location an unique identifier for the location - * where the exception was thrown - * @param current the current value - * @param lbound the minimum of the allowed values - * @param ubound the maximum of the allowed values - * @param message the reason. If NULL a generic - * message will be used - * @param logger if NULL the global logger will be used - */ - -ReRangeException::ReRangeException(ReLoggerLevel level, int location, - size_t current, size_t lbound, size_t ubound, const char* message, - ReLogger* logger) : - ReException(""){ - char buffer[64000]; - if (message == NULL) - message = "value outside limits"; - qsnprintf(buffer, sizeof buffer, "%s: %lu [%lu, %lu]", - message == NULL ? "" : message, current, lbound, ubound); - if (logger == NULL) - logger = ReLogger::globalLogger(); - logger->log(level, location, buffer); -} - -/** @class RplInvalidDataException rplexception.hpp "rplcore/rplexception.hpp" - * - * @brief An exception usable if binary data have the wrong structure. - * - * The data will be dumped as hex and ASCII dump. - * - * Note: If the logger is not given by parameter - * the usage of the global logger is not threadsafe. - */ - -/** - * @brief Constructor. - * - * This exception can be used if data does not have a given fomat. - * - * This constructor automatically logs the given data. This data - * will be dumped (hexadecimal dump and ASCII interpretation). - * - * @param level the logging level, e.g. LOG_ERROR - * @param location an unique identifier for the location - * where the exception was thrown - * @param message the reason - * @param data pointer to binary data - * @param dataSize the size of the data which should be dumped - * @param logger if NULL the global logger will be used - */ -RplInvalidDataException::RplInvalidDataException(ReLoggerLevel level, - int location, const char* message, const void* data, size_t dataSize, - ReLogger* logger) : - ReException(""){ - char buffer[64000]; - if (message == NULL) - message = "invalid data: "; - if (data == NULL) - data = ""; - if (dataSize > 16) - dataSize = 16; - size_t ix; - char* ptr = buffer + strlen(buffer); - for (ix = 0; ix < dataSize; ix++){ - qsnprintf(ptr, sizeof(buffer) - (ptr - buffer) - 1, "%02x ", - ((unsigned char*) data)[ix]); - ptr += strlen(ptr); - } - for (ix = 0; ix < dataSize; ix++){ - char cc = ((char*) data)[ix]; - if (cc > ' ' && cc <= '~') - *ptr++ = cc; - else - *ptr++ = '.'; - } - if (logger == NULL) - logger = ReLogger::globalLogger(); - logger->log(level, location, buffer); -} - -/** - * @brief Constructor. - * - * @param message describes what is not implemented - */ -ReNotImplementedException::ReNotImplementedException(const char* message) : - ReException("not implemented: ", message){ - ReLogger::globalLogger()->log(LOG_ERROR, LOC_NOT_IMPLEMENTED_1, - getMessage()); -} diff --git a/base/ReException.hpp b/base/ReException.hpp deleted file mode 100644 index 03d3909..0000000 --- a/base/ReException.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ReException.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 REEXCEPTION_HPP -#define REEXCEPTION_HPP - -// the sources generated from QT include this file directly: -#ifndef RPLCORE_HPP -#include -#endif - -class ReException { -protected: - ReException(); -public: - ReException(const char* message, ...); - ReException(ReLoggerLevel level, int location, const char* message, - ReLogger* logger = NULL); - ReException(ReLoggerLevel level, int location, ReLogger* logger, - const char* message, ...); - const QByteArray& getMessage() const{ - return m_message; - } -protected: - QByteArray m_message; -}; - -class ReRangeException: public ReException { -public: - ReRangeException(ReLoggerLevel level, int location, size_t current, - size_t lbound, size_t ubound, const char* message = NULL, - ReLogger* logger = NULL); -}; - -class RplInvalidDataException: public ReException { -public: - RplInvalidDataException(ReLoggerLevel level, int location, - const char* message, const void* data = NULL, size_t dataSize = 0, - ReLogger* logger = NULL); -}; - -class ReNotImplementedException: public ReException { -public: - ReNotImplementedException(const char* message); -}; - -#endif // REEXCEPTION_HPP diff --git a/base/ReLogger.cpp b/base/ReLogger.cpp deleted file mode 100644 index 777b0aa..0000000 --- a/base/ReLogger.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/* - * ReLogger.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 - * A configurable logger for different output media. - */ -/** @file rplcore/rpllogger.hpp - * - * Definitions for a configurable logger for different output media. - */ -#include "base/rebase.hpp" -#include -#include - -enum { - LOC_ADD_APPENDER_1 = LOC_FIRST_OF(LOC_LOGGER), // 10101 -}; - -ReLogger* ReLogger::m_globalLogger = NULL; - -/** - * @brief Returns the global logger. - * - * If it does not exist it will be created (singleton). - * - * @return the global logger - */ -ReLogger* ReLogger::globalLogger(){ - if (m_globalLogger == NULL){ - m_globalLogger = new ReLogger(); - m_globalLogger->buildStandardAppender("globallogger"); - } - return m_globalLogger; -} -/** - * @brief Frees the resources of the global logger. - */ -void ReLogger::destroyGlobalLogger(){ - delete m_globalLogger; - m_globalLogger = NULL; -} - -/** @class ReAppender rpllogger.hpp "rplcore/rpllogger.hpp" - * - * @brief Puts the logging info to a medium (e.g. a file). - * - * This is an abstract base class. - */ - -/** - * @brief Constructor. - * - * @param name identifies the logger. Useful for ReLogger::findLogger() - */ -ReAppender::ReAppender(const QByteArray& name) : - m_name(name), m_level(LOG_INFO){ - -} -/** - * @brief Destructor. - */ -ReAppender::~ReAppender(){ -} - -/** - * Returns the name. - * - * @return the name of the instance - */ -const char* ReAppender::getName() const{ - return m_name.data(); -} - -/** - * @brief Sets the level. - * - * @param level - */ -void ReAppender::setLevel(ReLoggerLevel level){ - m_level = level; -} -/** - * @brief Returns the level. - * - * @return the level - */ -ReLoggerLevel ReAppender::getLevel() const{ - return m_level; -} -/** - * @brief Checks whether the current location should be logged. - * - * @param level the level of the location. - * @return true: the location level is greater or equals to the appender's level - */ -bool ReAppender::isActive(ReLoggerLevel level){ - return level <= m_level; -} - -/** - * @brief Sets or clears the automatic deletions. - * - * @param onNotOff the state of the auto deletion - */ -void ReAppender::setAutoDelete(bool onNotOff){ - m_autoDelete = onNotOff; -} - -/** - * @brief Returns the state of the auto deletion. - * - * @return true: the logger destroys the instance - */ -bool ReAppender::isAutoDelete() const{ - return m_autoDelete; -} - -/** @class ReLogger rpllogger.hpp "rplcore/rpllogger.hpp" - * - * @brief Implements a logger. - * - * The logger takes the call from the calling location. - * But the output assumes the class ReAppender, - * more exactly: a subclass from the abstract class - * ReAppender, - * - * For single threaded applications there is a possability of - * a global logger. In this case the logger can be got with the static - * method ReLogger::globalLogger(). - * - * Note: using the global logger is not threadsafe! - * - * Each call of the logger should be provided by a unique identifier - * named the location. This allows to find the error quickly. - */ - -/** - * @brief Constructor. - */ -ReLogger::ReLogger() : - // m_appenders(), - m_countAppenders(0), - m_stdPrefix(), - m_mutex(), - m_withLocking(false){ - memset(m_appenders, 0, sizeof m_appenders); -} - -/** - * @brief Destructor. - */ -ReLogger::~ReLogger(){ - for (size_t ix = 0; ix < m_countAppenders; ix++){ - ReAppender* appender = m_appenders[ix]; - if (appender->isAutoDelete()){ - delete appender; - } - m_appenders[ix] = NULL; - } -} -/** - * @brief Returns the first char of a logging line displaying the logging level. - * - * @param level the level to "convert" - * @return the assigned prefix char - */ -char ReLogger::getPrefixOfLevel(ReLoggerLevel level) const{ - char rc = ' '; - switch (level) { - case LOG_ERROR: - rc = '!'; - break; - case LOG_WARNING: - rc = '+'; - break; - case LOG_INFO: - rc = ' '; - break; - case LOG_DEBUG: - rc = '='; - break; - default: - rc = '?'; - break; - } - return rc; -} - -/** - * @brief Tests whether at least one appender is active for a given level. - * - * @param level level to test - * @return false: all appenders are not activated by this level
- * true: otherwise - */ -bool ReLogger::isActive(ReLoggerLevel level) const{ - bool rc = false; - for (size_t ix = 0; ix < m_countAppenders; ix++){ - ReAppender* appender = m_appenders[ix]; - if (appender->isActive(level)){ - rc = true; - break; - } - } - return rc; -} - -/** - * @brief Sets the log level for all appenders. - * - * @param level level to set - */ -void ReLogger::setLevel(ReLoggerLevel level){ - for (size_t ix = 0; ix < m_countAppenders; ix++){ - ReAppender* appender = m_appenders[ix]; - appender->setLevel(level); - } -} - -/** - * @brief Sets or clears the state "with locking". - * - * @param onNotOff true: the logger is thread save.
- * false: not thread save - */ -void ReLogger::setWithLocking(bool onNotOff){ - m_withLocking = onNotOff; -} - -/** - * @brief Returns the standard prefix of a logging line. - * - * If it does not exist it will be created. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @return the standard logging line prefix - */ -const QByteArray& ReLogger::getStdPrefix(ReLoggerLevel level, int location){ - if (m_stdPrefix.isEmpty()) - m_stdPrefix = buildStdPrefix(level, location); - return m_stdPrefix; -} - -/** - * @brief Logs (or not) the calling location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param message the logging message - * @return true: for chaining - */ -bool ReLogger::log(ReLoggerLevel level, int location, const char* message){ - m_stdPrefix = ""; - bool first = true; - for (size_t ix = 0; ix < m_countAppenders; ix++){ - ReAppender* appender = m_appenders[ix]; - if (appender->isActive(level)){ - if (first && m_withLocking) - m_mutex.lock(); - appender->log(level, location, message, this); - } - } - if (!first && m_withLocking) - m_mutex.unlock(); - return true; -} -/** - * @brief Logs (or not) the calling location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param message the logging message - * @return true: for chaining - */ -bool ReLogger::log(ReLoggerLevel level, int location, - const QByteArray& message){ - return log(level, location, message.data()); -} - -/** - * @brief Logs (or not) the calling location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param message the logging message - * @return true: for chaining - */ -bool ReLogger::log(ReLoggerLevel level, int location, const ReString& message){ - return log(level, location, message.toUtf8().data()); -} - -/** - * @brief Logs (or not) the calling location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param format the logging message with placeholders (like printf). - * @param ... the values of the placeholders (varargs) - * @return true: for chaining - */ -bool ReLogger::logv(ReLoggerLevel level, int location, const char* format, ...){ - char buffer[64000]; - va_list ap; - va_start(ap, format); - qvsnprintf(buffer, sizeof buffer, format, ap); - va_end(ap); - return log(level, location, buffer); -} - -/** - * @brief Logs (or not) the calling location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param format the logging message with placeholders (like printf). - * @param ... the values of the placeholders (varargs) - * @return true: for chaining - */ -bool ReLogger::logv(ReLoggerLevel level, int location, const QByteArray& format, - ...){ - char buffer[64000]; - va_list ap; - va_start(ap, format); - qvsnprintf(buffer, sizeof buffer, format, ap); - va_end(ap); - return log(level, location, buffer); -} - -/** - * @brief Logs (or not) the calling location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param format the logging message with placeholders (like printf). - * @param varlist variable arguments - * @return true: for chaining - */ -bool ReLogger::log(ReLoggerLevel level, int location, const char* format, - va_list& varlist){ - char buffer[64000]; - qvsnprintf(buffer, sizeof buffer, format, varlist); - return log(level, location, buffer); -} - -/** - * @brief Builds the standard prefix of a logging line. - * - * @param level the level of the location - * @param location an unique identifier of the location - */ -QByteArray ReLogger::buildStdPrefix(ReLoggerLevel level, int location){ - time_t now = time(NULL); - struct tm* now2 = localtime(&now); - char buffer[64]; - qsnprintf(buffer, sizeof buffer, "%c%d.%02d.%02d %02d:%02d:%02d (%d): ", - getPrefixOfLevel(level), now2->tm_year + 1900, now2->tm_mon + 1, - now2->tm_mday, now2->tm_hour, now2->tm_min, now2->tm_sec, location); - return QByteArray(buffer); -} - -/** - * @brief Adds an appender. - * - * @param appender appender to add - */ -void ReLogger::addAppender(ReAppender* appender){ - if (m_countAppenders < sizeof m_appenders / sizeof m_appenders[0]){ - m_appenders[m_countAppenders++] = appender; - }else{ - log(LOG_ERROR, LOC_ADD_APPENDER_1, "too many appenders"); - } -} - -/** - * @brief Returns the appender with a given name. - * - * @param name the appender's name - * - * @return NULL: no appender with this name is registered
- * otherwise: the wanted appender - */ -ReAppender* ReLogger::findAppender(const char* name) const{ - ReAppender* rc = NULL; - for (size_t ix = 0; ix < m_countAppenders; ix++){ - ReAppender* current = m_appenders[ix]; - if (strcmp(name, current->getName()) == 0){ - rc = current; - break; - } - } - return rc; -} - -/** - * @brief Builds the standard appender configured by a configuration file. - * - * @param config configuration file - * @param prefix the prefix of the key in the config file - * (in front of "name") - * @param defaultLogfilePrefix - * the prefix of the log file if no entry in the - * configuration file - */ -void ReLogger::buildStandardAppender(ReConfig* config, const char* prefix, - const char* defaultLogfilePrefix){ - QByteArray sPrefix(prefix); - QByteArray logFilePrefix = config->asString(sPrefix + "name", - defaultLogfilePrefix); - - int maxSize = config->asInt(+"maxsize", 10100100); - int maxCount = config->asInt(sPrefix + "maxfiles", 5); - buildStandardAppender(logFilePrefix, maxSize, maxCount); - QByteArray sLevel = config->asString(sPrefix + "level", "info"); - ReLoggerLevel level = LOG_INFO; - if (strcasecmp(sLevel.constData(), "error") == 0) - level = LOG_ERROR; - else if (strcasecmp(sLevel, "warning") == 0) - level = LOG_WARNING; - else if (strcasecmp(sLevel, "debug") == 0) - level = LOG_DEBUG; - setLevel(level); -} - -/** - * @brief Builds the standard appender for the instance: a console logger and a file logger. - * - * @param prefix the prefix of the log file name, e.g. /var/log/server - * @param maxSize the maximum of the file size - * @param maxCount the maximal count of files. If neccessary the oldest file will be deleted - */ -void ReLogger::buildStandardAppender(const QByteArray& prefix, int maxSize, - int maxCount){ - ReStreamAppender* streamAppender = new ReStreamAppender(stderr); - streamAppender->setAutoDelete(true); - addAppender((ReAppender*) streamAppender); - ReFileAppender* fileAppender = new ReFileAppender(prefix, maxSize, maxCount); - fileAppender->setAutoDelete(true); - addAppender((ReAppender*) fileAppender); -} - -/** @class ReStreamAppender rpllogger.hpp "rplcore/rpllogger.hpp" - * - * @brief Puts the logging info to a standard output stream. - * - * The possible streams are std::stdout or std::stderr - */ - -/** - * @brief Constructor. - */ -ReStreamAppender::ReStreamAppender(FILE* file, const char* appenderName) : - ReAppender(QByteArray(appenderName)), m_fp(file){ -} - -/** - * @brief Destructor. - */ -ReStreamAppender::~ReStreamAppender(){ - fflush(m_fp); -} - -/** - * @brief Logs (or not) the current location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param message the logging message - * @param logger the calling logger - */ -void ReStreamAppender::log(ReLoggerLevel level, int location, - const char* message, ReLogger* logger){ - const QByteArray& prefix = logger->getStdPrefix(level, location); - fputs(prefix, m_fp); - fputs(message, m_fp); - fputc('\n', m_fp); - fflush(m_fp); -} -#pragma GCC diagnostic warning "-Wunused-parameter" - -/** @class ReFileAppender rpllogger.hpp "rplcore/rpllogger.hpp" - * - * @brief Puts the logging info to a file. - * - * The appender creates a collection of files to limit the used disk space. - * Each logfile is limited to a given size. And the number of files is limited. - * If the count exceeds the oldest file will be deleted. - * - * Each logfile's name has a given name prefix, a running number - * and the suffix ".log", e.g. "globallogger.003.log". - */ - -/** - * @brief Constructor. - * - * @param prefix the prefix of the log file name, e.g. /var/log/server - * @param maxSize the maximum of the file size - * @param maxCount the maximal count of files. If neccessary the oldest file will be deleted - * @param appenderName the name of the appender. @see ReLogger::findAppender() - */ -ReFileAppender::ReFileAppender(const QByteArray& prefix, int maxSize, - int maxCount, const char* appenderName) : - ReAppender(QByteArray(appenderName)), - m_prefix(prefix), - m_maxSize(maxSize), - m_maxCount(maxCount), - m_currentSize(0), - m_currentNo(0), - m_fp(NULL){ - open(); -} - -/** - * @brief Destructor. - */ -ReFileAppender::~ReFileAppender(){ - if (m_fp != NULL){ - fclose(m_fp); - m_fp = NULL; - } -} - -/** - * @brief Opens the next log file. - */ -void ReFileAppender::open(){ - if (m_fp != NULL) - fclose(m_fp); - char fullName[512]; - qsnprintf(fullName, sizeof fullName, "%s.%03d.log", m_prefix.data(), - ++m_currentNo); - m_fp = fopen(fullName, "a"); - if (m_fp == NULL) - fprintf(stderr, "cannot open: %s\n", fullName); - else{ - //@ToDo - m_currentSize = 0; - } -} - -/** - * @brief Logs (or not) the current location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param message the logging message - * @param logger the calling logger - */ -#pragma GCC diagnostic ignored "-Wunused-parameter" -void ReFileAppender::log(ReLoggerLevel level, int location, const char* message, - ReLogger* logger){ - if (m_fp != NULL){ - const QByteArray& prefix = logger->getStdPrefix(level, location); - fputs(prefix, m_fp); - fputs(message, m_fp); - fputc('\n', m_fp); - fflush(m_fp); - } -} -#pragma GCC diagnostic warning "-Wunused-parameter" - -/** @class ReMemoryAppender rpllogger.hpp "rplcore/rpllogger.hpp" - * - * @brief Puts the logging info to an internal buffer. - * - * This line list can be required: getLines(). - */ - -/** - * @brief Constructor. - * - * @param maxLines the maximum of lines. - * If the buffer is full the oldest lines will be deleted - * @param appenderName NULL or the name of the appender - */ -ReMemoryAppender::ReMemoryAppender(int maxLines, const char* appenderName) : - ReAppender(appenderName), - m_lines(), - m_maxLines(maxLines), - m_addPrefix(true){ - m_lines.reserve(maxLines); -} - -/** - * @brief Destructor. - */ -ReMemoryAppender::~ReMemoryAppender(){ -} - -/** - * Logs (or not) the current location. - * - * @param level the level of the location - * @param location an unique identifier of the location - * @param message the logging message - * @param logger the calling logger - */ -#pragma GCC diagnostic ignored "-Wunused-parameter" -void ReMemoryAppender::log(ReLoggerLevel level, int location, - const char* message, ReLogger* logger){ - if (m_lines.size() >= m_maxLines) - m_lines.removeFirst(); - if (!m_addPrefix) - m_lines.append(message); - else{ - QByteArray msg(logger->getStdPrefix(level, location)); - msg += message; - m_lines.append(msg); - } -} -#pragma GCC diagnostic warning "-Wunused-parameter" - -/** - * @brief Returns the list of lines. - * - * @return the line list - */ -const QList & ReMemoryAppender::getLines() const{ - return m_lines; -} - -/** - * @brief Deletes all log lines. - */ -void ReMemoryAppender::clear(){ - m_lines.clear(); -} diff --git a/base/ReLogger.hpp b/base/ReLogger.hpp deleted file mode 100644 index 310eb47..0000000 --- a/base/ReLogger.hpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * ReLogger.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 RELOGGER_HPP -#define RELOGGER_HPP - -/** - * - */ -class ReLogger; -class ReConfig; -/** - * @brief Logging level: for controlling of the logging. - * - * Each logging location defines one of the following level. - * If the level of an appender is lower or equals to this level - * the logging is done. - */ -enum ReLoggerLevel { - LOG_ERROR = 10, ///< marks an error. - LOG_WARNING = 15, ///< marks a warning - LOG_INFO = 20, ///< marks an information - LOG_DEBUG = 25 ///< for debug purpose only -}; - -class ReAppender { -public: - ReAppender(const QByteArray& name); - virtual ~ReAppender(); -private: - // No copy constructor: no implementation! - ReAppender(const ReAppender& source); - // Prohibits assignment operator: no implementation! - ReAppender& operator =(const ReAppender& source); -public: - virtual void log(ReLoggerLevel level, int location, const char* message, - ReLogger* logger) = 0; - bool isActive(ReLoggerLevel level); - void setLevel(ReLoggerLevel level); - void setAutoDelete(bool onNotOff); - bool isAutoDelete() const; - ReLoggerLevel getLevel() const; - const char* getName() const; - -private: - // Name of the appender. Used to find the appender in a list of appenders - QByteArray m_name; - // only locations with a lower or equal level will be logged - ReLoggerLevel m_level; - // true: the logger destroys the instance. false: the deletion must be done outside of the logger - bool m_autoDelete; -}; - -class ReLogger { -public: - static ReLogger* globalLogger(); - static void destroyGlobalLogger(); -private: - // the standard logger, can be called (with globalLogger()) from each location - static ReLogger* m_globalLogger; -public: - ReLogger(); - virtual ~ReLogger(); -private: - // No copy constructor: no implementation! - ReLogger(const ReLogger& source); - // Prohibits assignment operator: no implementation! - ReLogger& operator =(const ReLogger& source); -public: - bool log(ReLoggerLevel level, int location, const char* message); - bool log(ReLoggerLevel level, int location, const QByteArray& message); - bool log(ReLoggerLevel level, int location, const ReString& message); - bool logv(ReLoggerLevel level, int location, const char* format, ...); - bool logv(ReLoggerLevel level, int location, const QByteArray& format, ...); - bool log(ReLoggerLevel level, int location, const char* format, - va_list& varlist); - void addAppender(ReAppender* appender); - ReAppender* findAppender(const char* name) const; - void buildStandardAppender(ReConfig* config, const char* prefix = "logfile.", - const char* defaultLoggerName = "logger"); - void buildStandardAppender(const QByteArray& prefix, - int maxSize = 10 * 1024 * 1024, int maxCount = 5); - QByteArray buildStdPrefix(ReLoggerLevel level, int location); - const QByteArray& getStdPrefix(ReLoggerLevel level, int location); - char getPrefixOfLevel(ReLoggerLevel level) const; - bool isActive(ReLoggerLevel level) const; - void setLevel(ReLoggerLevel level); - void setWithLocking(bool onNotOff); -private: - // the assigned appenders: - ReAppender* m_appenders[16]; - // the number of appenders in m_appenders: - size_t m_countAppenders; - // "" or the cache of the prefix of the current logging line: This can be reused by any appender. - QByteArray m_stdPrefix; - QMutex m_mutex; - bool m_withLocking; -}; - -/** - * Implements an appender which puts the messages to a standard stream: stdout or stderr - */ -class ReStreamAppender: public ReAppender { -public: - ReStreamAppender(FILE* stream, const char* appenderName = "FileAppender"); - virtual ~ReStreamAppender(); -public: - virtual void log(ReLoggerLevel level, int location, const char* message, - ReLogger* logger); -private: - // stdout or stderr: - FILE* m_fp; -}; - -/** - * Implements an appender which puts the messages to a file - */ -class ReFileAppender: public ReAppender { -public: - ReFileAppender(const QByteArray& name, int maxSize, int maxCount, - const char* appenderName = "FileAppender"); - virtual ~ReFileAppender(); -public: - void open(); - virtual void log(ReLoggerLevel level, int location, const char* message, - ReLogger* logger); - -private: - // prefix of the log file name. Will be appended by "..log" - QByteArray m_prefix; - // maximal size of a logging file: - int m_maxSize; - // maximal count of logging files. If neccessary the oldest file will be deleted. - int m_maxCount; - // the size of the current log file: - int m_currentSize; - // the number of the current log file: - int m_currentNo; - // the current log file: - FILE* m_fp; -}; - -/** - * Stores the log messages in a list. - */ -class ReMemoryAppender: public ReAppender { -public: - ReMemoryAppender(int maxLines = 1024, const char* appenderName = - "MemoryAppender"); - ~ReMemoryAppender(); -public: - virtual void log(ReLoggerLevel level, int location, const char* message, - ReLogger* logger); - const QList & getLines() const; - void clear(); -private: - QList m_lines; - // maximum count of m_lines. If larger the oldest lines will be deleted. - int m_maxLines; - // true: standard prefix (level + datetime) will be stored too. - bool m_addPrefix; -}; - -#endif // RELOGGER_HPP diff --git a/base/ReQStringUtil.cpp b/base/ReQStringUtil.cpp deleted file mode 100644 index 2f85a64..0000000 --- a/base/ReQStringUtil.cpp +++ /dev/null @@ -1,618 +0,0 @@ -/* - * ReQStringUtil.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Missed operation for ReStrings. - */ -/** @file rplcore/rplqstring.hpp - * - * @brief Definitions for missed operation for ReStrings. - */ -#include "base/rebase.hpp" -#include -#include -/** - * @brief Determines the length and vlaue of an integer. - * - * @param text the number as text - * @param start the first index to inspect - * @param radix the base of the number sytem: 8 (octal), 10 or 16 - * @param pValue OUT: the value of the integer. May be NULL - * - * @return <=0: no integer found - * otherwise: the length of the integer - */ -int ReQStringUtil::lengthOfUInt64(const ReString& text, int start, int radix, - quint64* pValue){ - int inputLength = text.size(); - int64_t value = 0; - int ix = start; - int cc; - if (radix == 10){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 10 + cc - '0'; - else - break; - ix++; - } - }else if (radix == 16){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 16 + cc - '0'; - else if (cc >= 'A' && cc <= 'F') - value = value * 16 + cc - 'A' + 10; - else if (cc >= 'a' && cc <= 'f') - value = value * 16 + cc - 'a' + 10; - else - break; - ix++; - } - }else if (radix == 8){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '7') - value = value * 8 + cc - '0'; - else - break; - ix++; - } - }else{ - throw ReException("ReQStringUtil::lengthOfInt(): wrong radix: %d", radix); - } - if (pValue != NULL) - *pValue = value; - return ix - start; -} -/** - * @brief Determines the length and value of an unsigned integer. - * - * @param text the number as text - * @param start the first index to inspect - * @param radix the base of the number sytem: 8 (octal), 10 or 16 - * @param pValue OUT: the value of the integer. May be NULL - * - * @return 0: no integer found - * otherwise: the length of the integer - */ -int ReQStringUtil::lengthOfUInt(const ReString& text, int start, int radix, - uint* pValue){ - quint64 value; - int rc = lengthOfUInt64(text, start, radix, &value); - if (pValue != NULL) - *pValue = (uint) value; - return rc; -} - -/** - * Skips a character in a text at a given position if it has an expected value. - * - * @param text text to inspect - * @param expected the character which is expected - * @param index IN/OUT: the position of the expected character. - * Will be incremented if the expected character is found - * @param length IN/OUT: IN: 0: do nothing
- * OUT: 0: the expected character was not found. - * otherwise: the length is incremented - */ -void ReQStringUtil::skipExpected(const ReString& text, QChar expected, - int& index, int& length){ - if (length == 0){ - // error state, do nothing - } else if (index >= text.length() || text[index] != expected){ - length = 0; - } else { - index++; - length++; - } -} - -/** - * Returns the length of a date in a string. - * - * The syntax of a time is 'dd.mm.yyyy' or 'yyyy.mm.dd'. - * - * @param text text to inspect - * @param start the first index in text to inspect - * @param value OUT: the value of the found date. Not changed if result is 0.
- * May be NULL - * @return 0: no date found
- * otherwise: the length of the date in the string - */ -int ReQStringUtil::lengthOfDate(const ReString& text, int start, QDate* value) -{ - uint day = 0; - uint month = 0; - uint year = 0; - int length = lengthOfUInt(text, start, 10, &year); - switch(length){ - case 1: - case 2: - day = year; - year = 0; - break; - case 4: - break; - default: - length = 0; - break; - } - int length2; - start += length; - skipExpected(text, '.', start, length); - if (length > 0){ - length2 = lengthOfUInt(text, start, 10, &month); - if (length2 < 1 || length2 > 2) - length = 0; - else { - start += length2; - length += length2; - } - } - skipExpected(text, '.', start, length); - if (year > 0){ - length2 = lengthOfUInt(text, start, 10, &day); - if (length2 < 1 || length2 > 2) - length = 0; - else { - start += length2; - length += length2; - } - } else{ - length2 = lengthOfUInt(text, start, 10, &year); - if (length2 != 4) - length = 0; - else { - start += length2; - length += length2; - } - } - if (day < 1 || day > 31 || month < 1 || month > 12 || year < 1970 || year > 2100) - length = 0; - if (length != 0 && value != NULL) - *value = QDate(year, month, day); - return length; -} - -/** - * Returns the length of a date and/or time in a string. - * - * @param text text to inspect - * @param start the first index in text to inspect - * @param allowDateOnly false: if the date is not followed by - * a time the result will be 0 - * @param allowTimeOnly false: if no date is found at the given - * text position the result will be 0 - * @param value the value of the found date. Not changed if result is 0.
- * May be NULL - * @return 0: no date found
- * otherwise: the length of the date in the string - */ -int ReQStringUtil::lengthOfDateTime(const ReString& text, int start, - bool allowDateOnly, bool allowTimeOnly, QDateTime* value) -{ - QDate date; - QTime time; - int length = lengthOfDate(text, start, &date); - if (length == 0){ - if (allowTimeOnly){ - date = QDate::currentDate(); - length = lengthOfTime(text, start, &time); - } - } else { - if (start + length + 1 + 3 <= text.length()) { - start += length; - int length2 = 0; - if (! text[start].isDigit()){ - QTime time2; - length2 = lengthOfTime(text, start + 1, &time2); - if (length2 == 0 && ! allowDateOnly) - length = 0; - else if (length2 > 0){ - length += 1 + length2; - time = time2; - } - } - } - } - if (length > 0 && value != NULL) - *value = QDateTime(date, time); - return length; -} -/** - * Returns the length of a time in a string. - * - * The syntax of a time is hh:mm[:ss] - * - * @param text text to inspect - * @param start the first index in text to inspect - * @param value OUT: the value of the found time. Not changed if result is 0.
- * May be NULL - * @return 0: no date found
- * otherwise: the length of the date in the string - */ -int ReQStringUtil::lengthOfTime(const ReString& text, int start, QTime* value) -{ - uint hour = 0; - uint minute = 0; - uint sec = 0; - int length = lengthOfUInt(text, start, 10, &hour); - if (length > 0 && hour > 23) - length = 0; - if (length > 0){ - start += length; - } - int length2; - skipExpected(text, ':', start, length); - if (length > 0){ - length2 = lengthOfUInt(text, start, 10, &minute); - if (length2 < 1 || length2 > 2 || minute >= 60) - length = 0; - else - start += length2, length += length2; - } - if (length > 0 && start < text.length() && text[start] == ':'){ - length++; - start++; - length2 = lengthOfUInt(text, start, 10, &sec); - if (length2 < 1 || length2 > 2 || sec >= 60) - length = 0; - else - start += length2, length += length2; - } - if (length != 0 && value != NULL) - *value = QTime(hour, minute, sec); - return length; -} - -/** - * @brief Determines the length and value of a floting point number. - * - * @param text the number as text - * @param start the first index to inspect - * @param pValue OUT: the value of the integer. May be NULL - * - * @return <=0: no real number found - * otherwise: the length of the floating point number - */ -int ReQStringUtil::lengthOfReal(const ReString& text, int start, qreal* pValue){ - int inputLength = text.size(); - qreal value = 0.0; - int cc; - int ix = start; - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 10 + (cc - '0'); - else - break; - ix++; - } - // found: a digit has been found (in front of or behind the '.' - bool found = ix > start; - if (ix < inputLength && text[ix].unicode() == '.'){ - ix++; - } - if (ix < inputLength && text[ix].isDigit()){ - found = true; - qreal divisor = 1; - qreal precision = 0; - while (ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){ - divisor *= 10; - precision = precision * 10 + cc - '0'; - ix++; - } - value += precision / divisor; - }else if (!found){ - ix = start; - } - if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){ - int savePoint = ix; - ix++; - bool negative = false; - if ((cc = text[ix].unicode()) == '+') - ix++; - else if (cc == '-'){ - ix++; - negative = true; - } - if (ix >= inputLength || !text[ix].isDigit()) - ix = savePoint; - else{ - int exponent = 0; - while (ix < inputLength && text[ix].isDigit()){ - exponent = exponent * 10 + text[ix].unicode() - '0'; - ix++; - } - if (negative) - value /= qPow(10, exponent); - else - value *= qPow(10, exponent); - } - } - if (pValue) - *pValue = value; - return found ? ix - start : 0; -} - -/** - * @brief Converts a ReString into an utf-8 string - * - * The expression qstring.toUtf8().constData() is not allowed - * in a variable argument list like sprintf. This is a thread save workaround. - * - * @param source string to convert - * @param buffer OUT: target buffer - * @param bufferSize size of the target buffer - * @return buffer - */ -char*ReQStringUtil::utf8(const ReString& source, char buffer[], - size_t bufferSize){ - QByteArray val = source.toUtf8(); - if (val.length() < (int) bufferSize) - bufferSize = val.length() + 1; - memcpy(buffer, val.constData(), bufferSize - 1); - buffer[bufferSize - 1] = '\0'; - return buffer; -} - -class ReParserException : public ReException { -public: - ReParserException(const QString& message) : - ReException(), - m_message(message){ - } -public: - QString m_message; -}; -/** - * Constructor. - * - * @param expr an expression, e.g. "10*1024kByte+5MiByte" - * @param unitList description of the allowed units with its factor
- * example: "kibyte:1024;kbyte:1000;mibyte:1048576;mbyte:1000000" - */ -ReUnitParser::ReUnitParser(const QString& expr, const char* unitList, bool parseAtOnce) : - m_result(0), m_expr(expr), m_message(), m_unitList(unitList){ - normalize(); - if (parseAtOnce) - parse(); -} - -/** - * Returns the result of the expression as a 64 bit integer. - * - * @param defaultValue the result if the expression was not valid - * @return defaultValue: the result was not valid
- * the result as a 64 bit integer - */ -int64_t ReUnitParser::asInt64(int64_t defaultValue){ - return m_message.isEmpty() ? m_result : defaultValue; -} -/** - * Returns the result of the expression as an integer. - * - * @param defaultValue the result if the expression was not valid - * @return defaultValue: the result was not valid
- * the result as an integer - */ -int ReUnitParser::asInt(int defaultValue){ - return m_message.isEmpty() ? (int) m_result : defaultValue; -} -/** - * Returns the result of the expression as floating point number. - * - * @param defaultValue the result if the expression was not valid - * @return defaultValue: the result was not valid
- * the result as a floating point - */ -real_t ReUnitParser::asReal(real_t defaultValue){ - return m_message.isEmpty() ? (real_t) m_result : defaultValue; -} - -/** - * Returns an empty string or the error message. - * - * @return "": no error occurred
- * otherwise: the error message - */ -const QString& ReUnitParser::errorMessage() const{ - return m_message; -} - -/** - * Returns whether the given expression is valid. - * - * @return true: the expression is valid, a result was calculated - */ -bool ReUnitParser::isValid() const{ - return m_message.isEmpty(); -} - -/** - * @brief Normalizes the internal stored unit expression. - */ -void ReUnitParser::normalize(){ - // Remove the blanks: - for (int ii = m_expr.length() - 1; ii >= 0; ii--){ - if (m_expr[ii].isSpace()) - m_expr.remove(ii, 1); - } - // 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, '+'); - } - } -} - -/** - * 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; - } -} - -/** - * Calculates the value of a number or a (number, unit) pair. - * - * @param value a non negative number or a number followed by a unit
- * only units defined in m_unitList are allowed
- * examples: "4kByte" returns 4000, "4kibyte" returns 4096 - * @return the value of the number multiplied by the factor given by the unit - * @throws ReParserException - */ -uint64_t ReUnitParser::valueOf(const QString& value) const{ - uint64_t rc = 0; - int ix = ReQStringUtil::lengthOfUInt64(value, 0, 10, &rc); - if (ix == 0) - throw ReParserException(QObject::tr("number expected: ") + value); - QString unit = value.mid(ix); - if (! unit.isEmpty()){ - QStringList units = QString(m_unitList).split(";"); - QStringList::const_iterator it; - bool found = false; - for (it = units.begin(); it != units.end(); ++it){ - QStringList pair = it->split(":"); - if (pair.count() == 0) - throw ReParserException(QObject::tr("missing ':' in unit definition, e.g. 'k:1000': ") + *it); - if (pair.count() > 2) - throw ReParserException(QObject::tr("too many ':' in unit definition: ") + *it); - bool ok = false; - QString unit2 = *pair.begin(); - QString factor = *++pair.begin(); - uint64_t nFactor = factor.toLongLong(&ok); - if (! ok) - throw ReParserException(QObject::tr("not a number: ") + factor); - if (unit2.startsWith(unit)){ - rc *= nFactor; - found = true; - break; - } - } - if (! found) - throw ReParserException(QObject::tr("unknown unit, allowed: ") + QString(m_unitList)); - } - return rc; -} - -/** - * 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("", "minutes:60;hours:3600;days:86400;weeks:604800", false){ - parseDateTime(expr); -} - -/** - * Returns the parser result as a QDateTime instance. - * - * @return the parse result. If invalid input the result is the begin of the epoche - */ -QDateTime ReDateTimeParser::asDateTime() const -{ - return m_dateTime; -} - -/** - * Parses a date/time expression. - * - * Syntax: { "now" | [