]> gitweb.hamatoma.de Git - reqt/commitdiff
dayly work
authorhama <hama@siduction.net>
Sun, 29 Nov 2015 22:42:12 +0000 (23:42 +0100)
committerhama <hama@siduction.net>
Sun, 29 Nov 2015 22:42:12 +0000 (23:42 +0100)
appl/reidos/maincmdline.cpp [new file with mode: 0644]
appl/reidos/reidoscmdline.hpp [new file with mode: 0644]
appl/reidos/reidoscmdline.pro [new file with mode: 0644]
base/ReProgramArgs.cpp [new file with mode: 0644]
base/ReProgramArgs.hpp [new file with mode: 0644]
base/ReStringUtils.cpp
base/ReStringUtils.hpp
base/rebase.hpp
cunit/cuReStringUtils.cpp
cunit/cunit.pro

diff --git a/appl/reidos/maincmdline.cpp b/appl/reidos/maincmdline.cpp
new file mode 100644 (file)
index 0000000..38b203c
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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 "reidoscmdline.hpp"
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+       QApplication a(argc, argv);
+       QString startDir = argc > 1 ? argv[1] : "";
+       QString homeDir = argc > 2 ? argv[2] : "";
+
+       return a.exec();
+}
diff --git a/appl/reidos/reidoscmdline.hpp b/appl/reidos/reidoscmdline.hpp
new file mode 100644 (file)
index 0000000..c725455
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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 REIDOSCMDLINE_HPP
+#define REIDOSCMDLINE_HPP
+#include "base/rebase.hpp"
+#include "os/reos.hpp"
+#include "gui/regui.hpp"
+
+#endif // REIDOSCMDLINE_HPP
+
diff --git a/appl/reidos/reidoscmdline.pro b/appl/reidos/reidoscmdline.pro
new file mode 100644 (file)
index 0000000..b134310
--- /dev/null
@@ -0,0 +1,44 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-09-14T18:00:57
+#
+#-------------------------------------------------
+
+QT       += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = reidos
+TEMPLATE = app
+
+INCLUDEPATH += . ../..
+
+SOURCES += \
+        ../../gui/ReEdit.cpp \
+        ../../gui/ReStateStorage.cpp \
+        ../../gui/ReSettings.cpp \
+        ../../gui/ReFileTree.cpp \
+        ../../gui/ReGuiValidator.cpp \
+        ../../base/ReMatcher.cpp \
+        ../../base/ReFile.cpp \
+        ../../base/ReStringUtils.cpp \
+        ../../base/ReRandomizer.cpp \
+        ../../os/ReFileSystem.cpp \
+        ../../os/ReCryptFileSystem.cpp \
+       ../../base/ReLogger.cpp \
+       ../../base/ReQStringUtils.cpp \
+       ../../base/ReFileUtils.cpp \
+       ../../base/ReException.cpp \
+       ../../base/ReProgramArgs.cpp \
+       maincmdline.cpp
+
+HEADERS  +=  ../../base/rebase.hpp \
+        ../../gui/regui.hpp \
+        ../../gui/ReEdit.hpp \
+        ../../gui/ReStateStorage.hpp \
+        ../../gui/ReSettings.hpp \
+       ../../base/ReStringUtils.hpp \
+       ../../base/ReQStringUtils.hpp \
+       ../../base/ReException.hpp \
+       ../../os/reos.hpp
+       reidoscmdline.hpp
diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp
new file mode 100644 (file)
index 0000000..5e90c2c
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * ReProgramArgs.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"
+
+const char* ReProgramArgs::PREFIX_LINE_OPTION = "   ";
+
+/** @brief Constructor.
+ *
+ * @param caller       the object which throw the exception.
+ * @param message      the error message with placeholders like sprintf()
+ * @param ...
+ */
+ReOptionException::ReOptionException(ReProgramArgs* caller, const char* format,
+       ...) :
+               ReException() {
+       char buffer[64*1024];
+       va_list ap;
+       va_start(ap, format);
+       qvsnprintf(buffer, sizeof buffer, format, ap);
+       va_end(ap);
+       m_message = buffer;
+       if (caller != NULL)
+               caller->setLastError(m_message);
+}
+
+/** @brief Constructor.
+ *
+ * @param caller       the object which throw the exception
+ * @param message      the error message
+*/
+ReOptionException::ReOptionException(ReProgramArgs* caller, const QString& message) :
+       ReException()
+{
+       m_message = message.toUtf8();
+       if (caller != NULL)
+               caller->setLastError(m_message);
+}
+
+/** @brief Constructor.
+ *
+ * @param usage                a string array with the description of the usage.
+ *                                     Every string will be issued in a separate line
+ * @param examples     a string with one ore more calling examples.
+ *                                     Every string will be issued in a separate line
+ */
+ReProgramArgs::ReProgramArgs(const char* usageList[], const char* examples[]) :
+               m_usage(),
+               m_examples(),
+               m_options(),
+               m_args(NULL),
+               m_argCount(0),
+               m_program(NULL),
+               m_lastError(ReStringUtils::m_empty) {
+       QByteArray line;
+       for (const char** argv = usageList; *argv != NULL; argv++) {
+               line = *argv;
+               ReStringUtils::chomp(line);
+               m_usage.append(line.constData());
+       }
+       if (examples != NULL) {
+               for (const char** argv = examples; *argv != NULL; argv++) {
+                       if (strncmp(*argv, "$0", 2) != 0)
+                               m_examples.append(*argv);
+                       else {
+                               QByteArray line;
+                               line.append(m_program, -1);
+                               m_examples.append(line.constData() + 2);
+                       }
+               }
+       }
+}
+
+/** @brief Constructor.
+ *
+ * @param usage                a string with the description of the usage
+ *                                     It may contain <code>'\\n'</code> for separate lines
+ * @param examples     a string with one ore more calling examples.
+ *                                     It may contain <code>'\\n'</code> for separate lines
+ */
+ReProgramArgs::ReProgramArgs(const char* usageString, const char* examples) :
+               m_usage(),
+               m_examples(),
+               m_options(),
+               m_args(NULL),
+               m_argCount(0),
+               m_program("?"),
+               m_lastError() {
+       m_usage = QByteArray(usageString).split('\n');
+       if (examples != NULL) {
+               if (strstr(examples, "$0") == NULL)
+                       m_examples = QByteArray(examples).split('\n');
+               else {
+                       QByteArray line;
+                       line = examples;
+                       line.replace("$0", m_program);
+                       m_examples = line.split('\n');
+               }
+
+       }
+}
+/** @brief Destructor.
+ */
+ReProgramArgs::~ReProgramArgs() {
+}
+
+/**
+ * Sets the usage message.
+ *
+ * @param usage     a vector of lines without '\n'
+ */
+void ReProgramArgs::setUsage(const char* usage[]) {
+       m_usage.clear();
+       for (int ix = 0; usage[ix] != NULL; ix++)
+               m_usage.append(usage[ix]);
+}
+/** @brief Puts the property infos into the property string.
+ *
+ * The <strong>property string</strong> is a string stored in the hashlist.
+ * It contains all infos about the option but the current value.
+ *
+ * @param name                 the name of the option. Used in the methods <code>getInt()</code>, ...
+ * @param description  a short description of the option. Used in the user messages
+ * @param shortOpt             the one character option identifier. Used in the arguments. Must be preceded by '-'
+ * @param longOpt              the multi character option identifier.  Used in the arguments. Must be preceded by '--'
+ * @param dataType             the data type of the option: DT_INT, DT_BOOL ...
+ * @param defaultValue the default value of the option
+ * @param lengthValue  the length of <code>defaultValue</code>
+ */
+void ReProgramArgs::addProperties(const char*name, const char* description,
+       char shortOpt, const char* longOpt, DataType dataType,
+       const char* defaultValue, size_t lengthValue) {
+       ReProgOptionMap::const_iterator it;
+       for (it = m_options.cbegin(); it != m_options.cend(); ++it){
+               if (name == it.key()){
+                       throw ReOptionException(this, QObject::tr("name defined twice: %1").arg(name));
+               } else {
+                       ReProgOption* opt = it.value();
+                       if (shortOpt == opt->m_shortName)
+                               throw ReOptionException(this, QObject::tr("short option defined twice: %1").arg(shortOpt));
+                       else if (opt->m_longName == longOpt)
+                               throw ReOptionException(this, QObject::tr("long option defined twice: %1").arg(longOpt));
+               }
+       }
+       ReProgOption* opt = new ReProgOption;
+       opt->m_name = name;
+       opt->m_longName = longOpt;
+       opt->m_defaultValue = defaultValue;
+       opt->m_shortName = shortOpt;
+       opt->m_type = dataType;
+       // Mark current value as default:
+       opt->m_value = QByteArray("!") + defaultValue;
+}
+
+/** @brief Adds an option with a boolean value.
+ *
+ * @param name                 the name of the option. Used in the methods <code>getBool()</code>
+ * @param description  a short description of the option. Used in the user messages
+ * @param shortOpt             the one character option identifier. Used in the arguments. Must be preceded by '-'
+ * @param longOpt              the multi character option identifier.  Used in the arguments. Must be preceded by '--'
+ * @param defaultValue the default value of the option.
+ *
+ * @see getBool()
+ */
+void ReProgramArgs::addBool(const char* name, const char* description,
+       char shortOpt, const char* longOpt, bool defaultVal) {
+       addProperties(name, description, shortOpt, longOpt, DT_BOOL,
+               defaultVal ? "t" : "f", 1);
+}
+
+/** @brief Adds an option with an integer value.
+ *
+ * @param name                 the name of the option. Used in the methods <code>getInt()</code>
+ * @param description  a short description of the option. Used in the user messages
+ * @param shortOpt             the one character option identifier. Used in the arguments. Must be preceded by '-'
+ * @param longOpt              the multi character option identifier.  Used in the arguments. Must be preceded by '--'
+ * @param defaultValue the default value of the option
+ *
+ * * @see getInt()
+ */
+void ReProgramArgs::addInt(const char* name, const char* description,
+       char shortOpt, const char* longOpt, int defaultVal) {
+       QByteArray number = QByteArray::number(defaultVal);
+       addProperties(name, description, shortOpt, longOpt, DT_INT, number.constData(),
+               number.length());
+}
+
+/** @brief Adds an option with a string value.
+ *
+ * @param name                 the name of the option. Used in the methods <code>getString()</code>
+ * @param description  A short description of the option. Used in the user messages
+ * @param shortOpt             the one character option identifier. Used in the arguments. Must be preceded by '-'
+ * @param longOpt              the multi character option identifier.  Used in the arguments. Must be preceded by '--'
+ * @param defaultValue the default value of the option
+ *
+ * @see getString()
+ */
+void ReProgramArgs::addString(const char* name, const char* description,
+       char shortOpt, const char* longOpt, bool mayBeEmpty,
+       const char* defaultVal) {
+       addProperties(name, description, shortOpt, longOpt,
+               mayBeEmpty ? DT_STRING_EMPTY : DT_STRING, defaultVal,
+               defaultVal == NULL ? 0 : strlen(defaultVal));
+}
+
+/** @brief Analyses a long name option.
+ *
+ * The syntax of an long name option is --name or --name=value
+ *
+ * @param opt          the option string without --
+ *
+ */
+void ReProgramArgs::analyseLong(const char* opt) {
+
+       QByteArray name;
+       const char* value = strchr(opt, '=');
+       if (value == NULL)
+               name = opt;
+       else {
+               name = QByteArray(opt).mid(0, value - opt);
+               value++;
+       }
+       ReProgOption* option = m_options[name];
+
+       switch (option->m_type) {
+       case DT_INT:
+               if (value == NULL)
+                       throw ReOptionException(this,
+                               QObject::tr("Option %1: parameter expected. Use --%1=number").arg(name.constData()));
+               else
+                       option->m_value = value;
+               break;
+       case DT_STRING:
+               if (value == NULL)
+                       throw ReOptionException(this,
+                               QObject::tr("Option %1: parameter expected. Use --%1=string").arg(name.constData()));
+               option->m_value = value;
+               break;
+       case DT_STRING_EMPTY:
+               if (value == NULL)
+                       value = "";
+               option->m_value = value;
+               break;
+       case DT_BOOL: {
+               const char* boolValue = "f";
+               if (value == NULL
+                       || ReStringUtils::isInList(value, ";y;yes;t;true", true,
+                               ReStringUtils::AUTO_SEPARATOR))
+                       boolValue = "t";
+               else if (!ReStringUtils::isInList(value, ";n;no;f;false",
+                       true, ReStringUtils::AUTO_SEPARATOR))
+                       throw ReOptionException(this,
+                               QObject::tr("Option %1: Not a boolean value: %2. Use true or false")
+                               .arg(name.constData()).arg(value));
+               // Invert the default value:
+               if (option->m_defaultValue == "t")
+                       boolValue = boolValue[0] == 't' ? "f" : "t";
+               option->m_value = boolValue;
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/** @brief Analyses one or more short name options.
+ *
+ * Multiple short name options can be written in one word:
+ * <p>Example: -x -y -z can be noted as -xyz</p>
+ * <p>On the other side an option with parameter can be written in two forms:</p>
+ * <ul>
+ * <li>-xABC</li>
+ * <li>-x ABC</li>
+ * </ul>
+ *
+ * @param opt          an option string
+ * @param nextArg      the next argument behind the current option string.
+ *                                     May be NULL (no more arguments)
+ *
+ * @return     true a second word has been used: It was a parameter of an string or integer option.<br>
+ *                     false: The next argument has not been used
+ */
+bool ReProgramArgs::analyseShort(const char* opt, const char* nextArg) {
+       bool rc = false;
+       QByteArrayList properties;
+       bool again;
+       do {
+               again = false;
+
+               ReProgOption* option = search(opt[0], NULL);
+
+               // Forget the option short name:
+               opt++;
+               switch (option->m_type) {
+               case DT_INT:
+               case DT_STRING:
+               case DT_STRING_EMPTY:
+                       if (opt[0] != '\0') {
+                               setValue(opt->m_name, opt, option->m_type);
+                       } else {
+                               if (nextArg == NULL || nextArg[0] == '-') {
+                                       if (dataType[0] == DT_STRING_EMPTY)
+                                               setValue(nameStr, "", dataType);
+                                       else
+                                               throw ReOptionException(this,
+                                                       i18n(
+                                                               "Option $1 has type $2! There is no parameter."),
+                                                       nameStr, dataType);
+                               } else {
+                                       setValue(nameStr, nextArg, dataType);
+                                       rc = true;
+                               }
+                       }
+                       break;
+               case DT_BOOL: {
+                       // Get the current value:
+                       const char* value = "t";
+                       if (opt[0] == '-') {
+                               opt++;
+                               value = "f";
+                       } else if (opt[0] == '+')
+                               opt++;
+                       // Invert the default value:
+                       if (properties.strOf(IxDefault)[0] == 't')
+                               value = value[0] == 't' ? "f" : "t";
+                       setValue(nameStr, value, dataType);
+                       again = opt[0] != '\0';
+                       break;
+               }
+               default:
+                       break;
+               }
+       } while (again);
+       return rc;
+}
+
+/** @brief Returns a not option argument given by an index.
+ *
+ * @param index                the index of the wanted program argument which is not an option.
+ *
+ * @return                     NULL: wrong index<br>
+ *                                     otherwise: the wanted argument.
+ */
+const char* ReProgramArgs::arg(size_t index) const {
+       const char* rc = NULL;
+
+       if (index < (size_t) m_argCount)
+               rc = m_args[index];
+       return rc;
+}
+
+/** @brief Returns the count of arguments (without options).
+ *
+ * @return the count of arguments
+ */
+int ReProgramArgs::argCount() const {
+       return m_argCount;
+}
+
+/** @brief Returns the value of a boolean option.
+ *
+ * @param name Name of the option.
+ *
+ * @return The value of the option set in the programs arguments or the default value.
+ *
+ * @throws ReOptionException   Unknown name or wrong type.
+ */
+bool ReProgramArgs::getBool(const char* name) {
+       ReProgOption* option = m_options.value(name, NULL);
+       if (option == NULL)
+               throw ReOptionException(this, QObject::tr("%1 is not an option name").arg(name));
+       if (option->m_type != DT_BOOL)
+               throw ReOptionException(this,
+                       QObject::tr("%1 is not an boolean option. Type is %2").arg(name)
+                       .arg(option->m_type));
+       bool rc = option->m_value.at(1) == 't';
+       return rc;
+}
+
+/** @brief Returns the value of an integer option.
+ *
+ * @param name Name of the option.
+ *
+ * @return The value of the option set in the programs arguments or the default value.
+ *
+ * @throws ReOptionException   Unknown name or wrong type.
+ */
+int ReProgramArgs::getInt(const char* name) {
+       ReProgOption* option = m_options.value(name, NULL);
+       if (option == NULL)
+               throw ReOptionException(this, QObject::tr("%1 is not an option name").arg(name));
+       if (option->m_type != DT_BOOL)
+               throw ReOptionException(this,
+                       QObject::tr("%1 is not an integer option. Type is %2").arg(name)
+                       .arg(option->m_type));
+       // Note: first char is a tag: '!': default
+       int rc = atoi(option->m_value.constData() + 1);
+       return rc;
+}
+
+/** @brief Returns the value of a string option.
+ *
+ * @param name Name of the option.
+ *
+ * @return The value of the option set in the programs arguments or the default value.
+ *
+ * @throws ReOptionException   Unknown name or wrong type.
+ */
+const char* ReProgramArgs::getString(const char* name, QByteArray& buffer) {
+       ReProgOption* option = m_options.value(name, NULL);
+       if (option == NULL)
+               throw ReOptionException(this, QObject::tr("%1 is not an option name").arg(name));
+       if (option->m_type != DT_STRING && option->m_type != DT_STRING_EMPTY)
+               throw ReOptionException(this,
+                       QObject::tr("%1 is not an string option. Type is %2").arg(name)
+                       .arg(option->m_type));
+       // Note: first char is a tag: '!': default
+       buffer = option->m_value.mid(1);
+       return buffer.constData();
+}
+
+/**
+ * Issues a help message.
+ *
+ * @param message                      message to show
+ * @param issueLastError       <code>true</code>: the last OS error will be shown
+ * @param lines                                OUT: a stringlist for the help message
+ */
+void ReProgramArgs::help(const char* message, bool issueLastError,
+       ReStringList& lines) const {
+       lines.append(m_usage);
+       lines.append("");
+
+       ReArrayPosition position;
+       if (m_properties.next(position, NULL, NULL)) {
+               lines.append(i18n("<options>:"));
+       }
+       QByteArray name;
+       QByteArray prop;
+       QByteArray line;
+       QByteArray param;
+
+       while (m_properties.next(position, &name, &prop)) {
+               ReStringList properties(512, 1024, 2, 2);
+               properties.split(prop.constData(), '\1');
+               line.setLength(0);
+               DataType dataType = DataType(properties.strOf(IxType)[0]);
+               const char* shortName = properties.strOf(IxShort);
+               param.setLength(0);
+               switch (dataType) {
+               case DT_INT:
+                       param.append(i18n("<number>"), -1);
+                       break;
+               case DT_STRING:
+                       param.append(i18n("<not empty string>"), -1);
+                       break;
+               case DT_STRING_EMPTY:
+                       param.append(i18n("[<string>]"), -1);
+                       break;
+               default:
+                       break;
+               }
+               if (shortName[0] != HIDDEN_SHORT_NAME) {
+                       line.append("-", 1).append(shortName, 1);
+                       line.append(param.constData(), -1).appendChar(' ').append(i18n(" or "),
+                               -1);
+               }
+               line.append(i18n("--"), -1).append(properties.strOf(IxLong), -1);
+               if (param.length() > 0) {
+                       line.append("=", -1).append(param.constData(), -1);
+                       if (dataType != DT_STRING
+                               || properties.strLengthOf(IxDefault) > 0) {
+                               line.append(i18n(" Default value: "), -1);
+                               if (dataType == DT_STRING)
+                                       line.appendChar('\'');
+                               line.append(properties.strOf(IxDefault), -1);
+                               if (dataType == DT_STRING)
+                                       line.appendChar('\'');
+                       }
+               }
+               lines.append(line.constData());
+               line.set(PREFIX_LINE_OPTION, -1).append(properties.strOf(IxDescr), -1);
+               lines.append(line.constData());
+       }
+       if (m_examples.count() > 0) {
+               lines.append(i18n("Example(s):"));
+               lines.append(m_examples);
+       }
+       if (issueLastError && m_lastError.length() > 0) {
+               line.set("+++ ", 4).append(m_lastError.constData(), -1);
+               lines.append(line.constData());
+       }
+
+       if (message != NULL && message[0] != '\0') {
+               line.set("+++ ", 4).append(message, -1);
+               lines.append(line.constData());
+       }
+}
+/**
+ * Issues a help message.
+ *
+ * @param message                      message to show
+ * @param issueLastError       <code>true</code>: the last OS error will be shown
+ * @param stream                       OUT: output stream, e.g. stderr
+ */
+void ReProgramArgs::help(const char* message, bool issueLastError,
+       FILE* stream) const {
+       ReStringList lines(512, 1024, 8, 2);
+       help(message, issueLastError, lines);
+       for (size_t ii = 0; ii < lines.count(); ii++) {
+               fputs(lines.strOf(ii), stream);
+               fputc('\n', stream);
+       }
+}
+
+/** @brief Initializes the options from the program arguments.
+ *
+ * While arguments are preceded by an '-' they will be treated as options.
+ * The rest of arguments are stored for retrieving with <code>getArg()</code>.
+ *
+ * @param argc         The count of program arguments (inclusive options).
+ * @param argv         The argument vector.
+ *
+ * @throws ReException
+ */
+void ReProgramArgs::init(int argc, const char* argv[]) {
+       m_program = argv[0];
+       argv++;
+       argc--;
+
+       while (argc > 0 && argv[0][0] == '-') {
+               if (argv[0][1] == '-')
+                       analyseLong(argv[0] + 2);
+               else {
+                       if (analyseShort(argv[0] + 1, argc <= 1 ? NULL : argv[1]))
+                               argc--, argv++;
+               }
+               argc--;
+               argv++;
+       }
+       m_argCount = argc;
+       m_args = (const char**) argv;
+}
+
+/** @brief Returns the program name.
+ *
+ * @return The name of the application.
+ */
+const char* ReProgramArgs::programName() const {
+       return m_program;
+}
+
+/** @brief Search the property string of an option.
+ *
+ * @param shortName            The option`s short name. Not relevant if <code>longName != NULL</code>.
+ * @param LongName             The option`s long name. Not relevant if <code>longName == NULL</code>.
+ * @param name                 Out: The name of the option.
+ * @param list                 Out: The properties are returned in this list.
+ *
+ * @throws ReOptionException   Unknown option.
+ */
+void ReProgramArgs::search(char shortName, const char* longName,
+       QByteArray& name, ReStringList& list) {
+       ReArrayPosition position;
+       QByteArray properties;
+       bool found = false;
+       size_t lengthLongName = 0;
+       if (longName != NULL) {
+               const char* ptr;
+               if ((ptr = strchr(longName, '=')) != NULL)
+                       lengthLongName = ptr - longName;
+               else
+                       lengthLongName = strlen(longName);
+       }
+       while (!found && m_properties.next(position, &name, &properties)) {
+               list.split(properties.constData(), '\1');
+               if (longName == NULL && list.count() > IxShort
+                       && shortName == list.strOf(IxShort)[0])
+                       found = true;
+               else if (lengthLongName > 0 && list.count() > IxLong
+                       && list.sizeOf(IxLong) == lengthLongName + 1
+                       && strncmp(longName, list.strOf(IxLong), lengthLongName) == 0)
+                       found = true;
+       }
+       if (!found) {
+               if (longName == NULL)
+                       name.set(&shortName, 1);
+               else
+                       name.set(longName, lengthLongName);
+               throw ReOptionException(this, i18n("Unknown option: $1"), name.constData());
+       }
+}
+
+/** @brief Sets the last error message.
+ *
+ * @param message      The error message.
+ */
+void ReProgramArgs::setLastError(const char* message) {
+       m_lastError = message;
+}
+
+/** @brief Sets the last error message.
+ *
+ * @param message      The error message.
+ */
+void ReProgramArgs::setLastError(const QByteArray& message) {
+       m_lastError = message;
+}
+
+/** @brief Sets the option value.
+ *
+ * @param name         The option's name.
+ * @param value                The option's value.
+ * @param dataType     Theo option's data type.
+ */
+void ReProgramArgs::setValue(const char* name, const char* value,
+       DataType dataType) {
+       switch (dataType) {
+       case DT_INT:
+               if (strspn(value, "01234567890") != strlen(value))
+                       throw ReOptionException(this,
+                               QObject::tr("Option %1 expect an integer as parameter, not %2").arg(name)
+                               .arg(value));
+               break;
+       case DT_STRING:
+               if (value[0] == '\0')
+                       throw ReOptionException(this,
+                               QObject::tr("Option %1: Empty parameter is not allowed").arg(name));
+               break;
+       case DT_STRING_EMPTY:
+       case DT_BOOL:
+       default:
+               break;
+       }
+       QByteArray buffer;
+       // First character says: defined.
+       buffer.appendChar(' ').append(value, -1);
+       m_values.put(name, buffer.constData());
+}
+
diff --git a/base/ReProgramArgs.hpp b/base/ReProgramArgs.hpp
new file mode 100644 (file)
index 0000000..cdd6af8
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * ReProgramArgs.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 REPROGRAMARGS_H_
+#define REPROGRAMARGS_H_
+
+class ReProgramArgs;
+/** All errors will reported by this exception.
+ */
+class ReOptionException: public ReException {
+public:
+       ReOptionException(ReProgramArgs* caller, const char* format, ...);
+       ReOptionException(ReProgramArgs* caller, const QString& message);
+};
+
+class ReProgOption;
+typedef QMap<QByteArray, ReProgOption*> ReProgOptionMap;
+
+/**
+ * This class analyses the program arguments and give an interface for retrieving them.
+ *
+ * Program arguments contains the program name, possibly options and "true" arguments.
+ * <p>Options are short name options or long name options.</p>
+ * <p>A short name option is preceded by a single dash ('-'), a long name option starts with two dashes: (--).</p>
+ * <p>There are three types of options: boolean, integer and string.</p>
+ * <p>Every option must have an default value.</p>
+ * <p>A boolean option has normally a default value <code>false</code>. If it appears in the arguments
+ * it will be have the value <code>true</code>.</p>
+ * <p>An integer or string option can be followed by an integer or string value:<br>
+ * Short name option: -x value or -xvalue<br>
+ * Long name option: -xxx=value</p>
+ * <p>The program must contain a definition of the options: <code>addInt(), addBool() and/or addString()</code>,
+ * the analyse (<code>init()</code>) and the retrieval (<code>getInt(), getBool() and/or getString()</code>.</p>
+ * <p>The connection between definition and retrieval are names.</p>
+ */
+class ReProgramArgs {
+       static const char* PREFIX_LINE_OPTION;
+public:
+       enum DataType {
+               DT_UNDEF = 0,
+               DT_INT = 'i',
+               DT_BOOL = 'b',
+               DT_STRING = 's',
+               DT_STRING_EMPTY = 'S'
+       };
+       enum {
+               HIDDEN_SHORT_NAME = 2
+       };
+public:
+       ReProgramArgs(const char* usageList[], const char* examples[] = NULL);
+       ReProgramArgs(const char* usageString, const char* examples = NULL);
+       virtual ~ReProgramArgs();
+public:
+       void addBool(const char* name, const char* description, char shortOpt,
+               const char* longOpt, bool defaultVal);
+       void addInt(const char* name, const char* description, char shortOpt,
+               const char* longOpt, int defaultVal);
+       void addString(const char* name, const char* description, char shortOpt,
+               const char* longOpt, bool mayBeEmpty, const char* defaultVal);
+       int argCount() const;
+       const char* arg(size_t index) const;
+       bool getBool(const char* name);
+       int getInt(const char* name);
+       const char* getString(const char* name, QByteArray& buffer);
+       void help(const char* message, bool issueLastError,
+               QByteArrayList& lines) const;
+       void help(const char* message, bool issueLastError, FILE* stream) const;
+       void init(int argc, const char* argv[]);
+       const char* programName() const;
+       void setLastError(const char* message);
+       void setLastError(const QByteArray& message);
+       void setUsage(const char* usage[]);
+private:
+       void addProperties(const char*name, const char* description, char shortOpt,
+               const char* longOpt, DataType dataType, const char* defaultValue,
+               size_t lengthValue);
+       void analyseLong(const char* opt);
+       bool analyseShort(const char* opt, const char* nextArg);
+       ReProgOption* search(char shortName, const char* longName);
+       void setValue(const char* name, const char* value, DataType dataType);
+protected:
+       QByteArrayList m_usage;
+       QByteArrayList m_examples;
+       ReProgOptionMap  m_options;
+       const char** m_args;
+       int m_argCount;
+       const char* m_program;
+       QByteArray m_lastError;
+};
+
+class ReProgOption {
+public:
+       ReProgramArgs::DataType m_type;
+       QByteArray m_name;
+       QByteArray m_longName;
+       char m_shortName;
+       QByteArray m_value;
+       QByteArray m_defaultValue;
+};
+
+#endif /* REPROGRAMARGS_H_ */
index d6600742149b52b10b91b35dc84ad3267c3d37d5..3ec4fd9135f11e1f62bdc3a74f34754b347439d8 100644 (file)
  * This is a class with static members only.
  */
 
+const char ReStringUtils::AUTO_SEPARATOR = '\0';
+
 const QByteArray ReStringUtils::m_empty;
 
+/**
+ * Removes a given character from the end of the string if it is there.
+ *
+ * @param string       string to change
+ * @param cc           character to remove. Default: end of line ('\n')<br>
+ *                                     If <code>cc</code> is '\n' then also '\r' will be removed
+ *                                     at the end of the string
+ * @return                     <code>string</code>: for chaining
+ */
+QByteArray&ReStringUtils::chomp(QByteArray& string, char cc)
+{
+       int length;
+       if (string.length() > 0 && string.at(length = string.length() - 1) == cc)
+       {
+               string.resize(length);
+               if (cc == '\n' && length > 0 && string.at(--length) == '\r')
+                       string.resize(length);
+       }
+       return string;
+}
 /**
  * @brief Counts the occurrences of a given char in a string.
  *
@@ -33,6 +55,7 @@ const QByteArray ReStringUtils::m_empty;
  * @param cc   the char to count
  * @return             the number of <code>cc</code> in the text
  */
+
 int ReStringUtils::countChar(const char* line, char cc) {
        const char* ptr = line;
        int rc = 0;
@@ -119,6 +142,45 @@ char ReStringUtils::fileSeparatorChar() {
        return s_fileSeparator;
 }
 
+/** @brief Tests whether a phrase is in a phrase list.
+ *
+ * @param phrase               the word to search
+ * @param list                 the list to search. All phrases of the list are
+ *                                              separated by <code>separator</code>
+ * @param ignoreCase   <code>true</code>: The search is case insensitive<br>
+ *                                             <code>false</code>: The search is case sensitive
+ * @param separator            the separator in <code>list</code>.
+ *                                             If <code>AUTO_SEPARATOR</code> the separator will
+ *                                             be taken from the list itself (the first character)
+ */
+bool ReStringUtils::isInList(const char* phrase, const char* list,
+       bool ignoreCase, char separator) {
+       if (separator == AUTO_SEPARATOR)
+               separator = *list++;
+       const char* end = strchr(list, separator);
+       int phraseLength = strlen(phrase);
+       bool rc = false;
+       while (!rc && end != NULL) {
+               if (end - list == phraseLength) {
+                       if (ignoreCase)
+                               rc = strnicmp(list, phrase, phraseLength) == 0;
+                       else
+                               rc = strncmp(list, phrase, end - list) == 0;
+                       if (rc)
+                               break;
+               }
+               list = end + 1;
+               end = strchr(list, separator);
+       }
+       if (!rc) {
+               if (ignoreCase)
+                       rc = strnicmp(list, phrase, end - list) == 0;
+               else
+                       rc = strncmp(list, phrase, end - list) == 0;
+       }
+       return rc;
+}
+
 /**
  * Builds a hexadecimal dump.
  *
@@ -653,3 +715,4 @@ bool ReCharSet::fillIndexOf(const char* charSet, char minChar, char maxChar,
        }
        return rc;
 }
+
index ba2306b75a4cf373dee3e91d6c620c79d0abaef8..a3939c47ad973e81a04e5dede0de7b3e3f742ad6 100644 (file)
 #ifndef RPLSTRING_HPP
 #define RPLSTRING_HPP
 
+#ifdef __linux__
+#define strnicmp(trg, src, len) strncasecmp(trg, src, len)
+#elif __WIN32__
+#define strnicmp(trg, src, len) _strnicmp(trg, src, len)
+#endif
 class ReCharSet {
 public:
        ReCharSet(const char* indexToChar, int* charToIndex,
@@ -39,6 +44,7 @@ protected:
 
 class ReStringUtils {
 public:
+       static QByteArray& chomp(QByteArray &string, char cc = '\n');
        static int countChar(const char* line, char cc);
        static int count(const char* source, const char* item);
        static const QByteArray& cutString(const QByteArray& source, int maxLength,
@@ -50,6 +56,8 @@ public:
                16) {
                return hexDump((uint8_t*) data, length, bytesPerLine);
        }
+       static bool isInList(const char* phrase, const char* list, bool ignoreCase,
+                                 char separator = AUTO_SEPARATOR);
        static QByteArray read(const char* file, bool removeLastNewline = true);
        static QByteArray replaceNode(const char* source, const char* newNode);
        static bool write(const char* file, const char* content = NULL,
@@ -75,6 +83,11 @@ public:
 
 public:
        static const QByteArray m_empty;
+public:
+       /** If used in <code>isInList()</code> the first character of the list
+        * will be the separator.
+        */
+       static const char AUTO_SEPARATOR;
 };
 
 #endif // RPLSTRING_HPP
index 1c5a26fe8f64d5232ef3bace9d2fbc9ece717a21..ae366b515d7a869873f858ff88fbc1d8c2132d98 100644 (file)
@@ -158,6 +158,7 @@ inline int roundInt(double value) {
 #include "base/ReWriter.hpp"
 #include "base/ReLogger.hpp"
 #include "base/ReException.hpp"
+#include "base/ReProgramArgs.hpp"
 #include "base/ReContainer.hpp"
 #include "base/ReStringUtils.hpp"
 #include "base/ReQStringUtils.hpp"
index bb987ab9971a3464a071a621f61146000e876932..ae67b4f5bc4929b6c3a9e92c2f99488c48f78808 100644 (file)
@@ -185,7 +185,55 @@ public:
                checkEqu(2.5, value);
        }
 
+       void testChomp(){
+               QByteArray buffer;
+               buffer = "abc\n";
+               checkEqu("abc", ReStringUtils::chomp(buffer).constData());
+               buffer = "abc\r\n";
+               checkEqu("abc", ReStringUtils::chomp(buffer).constData());
+               buffer = "abc/";
+               checkEqu("abc", ReStringUtils::chomp(buffer, '/').constData());
+               buffer = "\n";
+               checkEqu("", ReStringUtils::chomp(buffer).constData());
+               buffer = "";
+               checkEqu("", ReStringUtils::chomp(buffer).constData());
+               buffer = "";
+               checkEqu("", ReStringUtils::chomp(buffer, 'x').constData());
+       }
+
+       void testIsInList(){
+               // case sensitive, auto separator:
+               checkT(ReStringUtils::isInList("yes", ";ja;yes", false));
+               checkT(ReStringUtils::isInList("yes", ";ja;yes;si", false));
+               checkT(ReStringUtils::isInList("yes", ";yes;si", false));
+               // case sensitive, explicite separator:
+               checkT(ReStringUtils::isInList("yes", "ja;yes;si", false, ';'));
+               checkT(ReStringUtils::isInList("yes", "yes;si", false, ';'));
+               checkT(ReStringUtils::isInList("yes", "ja;yes", false, ';'));
+
+               // case insensitive, auto separator:
+               checkT(ReStringUtils::isInList("yes", ";ja;Yes", true));
+               checkT(ReStringUtils::isInList("YES", ";ja;yes;si", true));
+               checkT(ReStringUtils::isInList("yEs", ";yeS;si", true));
+               // case sensitive, explicite separator:
+               checkT(ReStringUtils::isInList("Yes", "ja;yes;si", true, ';'));
+               checkT(ReStringUtils::isInList("yes", "Yes;si", true, ';'));
+               checkT(ReStringUtils::isInList("YES", "ja;yes", true, ';'));
+
+               // substring
+               checkF(ReStringUtils::isInList("y", "ja;yes;si", true, ';'));
+               // sensitive
+               checkF(ReStringUtils::isInList("yes", "ja;Yes;si", false, ';'));
+
+               // 1 element list
+               checkT(ReStringUtils::isInList("yes", "yes", false, ';'));
+               checkT(ReStringUtils::isInList("yes", ";yes", false));
+
+       }
+
        virtual void run() {
+               testIsInList();
+               testChomp();
                testLengthOfReal();
                testLengthOfUInt64();
                testCountChar();
index 824a079c0def01b3d9bb55b2d9fa9f8b2a6c22eb..a3195c853573fa65292115fbbaa8680ac074fc9f 100644 (file)
@@ -58,7 +58,8 @@ SOURCES += main.cpp \
        cuReMatcher.cpp \
         allTests.cpp \
        ../base/ReProcess.cpp \
-       cuReProcess.cpp
+       cuReProcess.cpp \
+    ../base/ReProgramArgs.cpp
 
 HEADERS += \
         ../base/ReFile.hpp \