From: hama Date: Tue, 1 Dec 2015 23:38:28 +0000 (+0100) Subject: ReProgArgs works X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=d68d0e4b887dd24ec4974a29d8aa334216f500d2;p=reqt ReProgArgs works --- diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp index 5e90c2c..81ec08d 100644 --- a/base/ReProgramArgs.cpp +++ b/base/ReProgramArgs.cpp @@ -12,6 +12,7 @@ #include "base/rebase.hpp" const char* ReProgramArgs::PREFIX_LINE_OPTION = " "; +QByteArray ReProgramArgs::UNDEFINED_STRING("\01"); /** @brief Constructor. * @@ -122,6 +123,37 @@ void ReProgramArgs::setUsage(const char* usage[]) { for (int ix = 0; usage[ix] != NULL; ix++) m_usage.append(usage[ix]); } + +/** + * Converts a type into a string. + * + * @param dataType type to convert + * @return the type as string + */ +const char*ReProgramArgs::typeToString(ReProgramArgs::DataType dataType) +{ + const char* rc; + static QByteArray s_buffer; + switch(dataType){ + case DT_BOOL: + rc = "bool"; + break; + case DT_INT: + rc = "int"; + break; + case DT_STRING: + rc = "string"; + break; + case DT_STRING_EMPTY: + rc = "string(empty)"; + break; + default: + s_buffer = "unknown type (" + QByteArray::number(dataType) + ")"; + rc = s_buffer.constData(); + break; + } + return rc; +} /** @brief Puts the property infos into the property string. * * The property string is a string stored in the hashlist. @@ -137,14 +169,14 @@ void ReProgramArgs::setUsage(const char* usage[]) { */ void ReProgramArgs::addProperties(const char*name, const char* description, char shortOpt, const char* longOpt, DataType dataType, - const char* defaultValue, size_t lengthValue) { + const char* defaultValue) { 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) + if (shortOpt != 0 && 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)); @@ -156,8 +188,10 @@ void ReProgramArgs::addProperties(const char*name, const char* description, opt->m_defaultValue = defaultValue; opt->m_shortName = shortOpt; opt->m_type = dataType; + opt->m_description = description; // Mark current value as default: - opt->m_value = QByteArray("!") + defaultValue; + opt->m_value = defaultValue; + m_options[name] = opt; } /** @brief Adds an option with a boolean value. @@ -173,7 +207,7 @@ void ReProgramArgs::addProperties(const char*name, const char* description, 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); + defaultVal ? "t" : "f"); } /** @brief Adds an option with an integer value. @@ -189,8 +223,7 @@ void ReProgramArgs::addBool(const char* name, const char* description, 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()); + addProperties(name, description, shortOpt, longOpt, DT_INT, number.constData()); } /** @brief Adds an option with a string value. @@ -207,8 +240,8 @@ 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)); + mayBeEmpty ? DT_STRING_EMPTY : DT_STRING, + defaultVal == NULL ? UNDEFINED_STRING.constData() : defaultVal); } /** @brief Analyses a long name option. @@ -228,8 +261,10 @@ void ReProgramArgs::analyseLong(const char* opt) { name = QByteArray(opt).mid(0, value - opt); value++; } - ReProgOption* option = m_options[name]; - + ReProgOption* option = search(0, name); + if (option == NULL) + throw ReOptionException(this, QObject::tr("unknown option: %1") + .arg(name.constData())); switch (option->m_type) { case DT_INT: if (value == NULL) @@ -242,6 +277,9 @@ void ReProgramArgs::analyseLong(const char* opt) { if (value == NULL) throw ReOptionException(this, QObject::tr("Option %1: parameter expected. Use --%1=string").arg(name.constData())); + else if (value[0] == '\0') + throw ReOptionException(this, + QObject::tr("Option %1: empty string is not allowed. Use --%1=string").arg(name.constData())); option->m_value = value; break; case DT_STRING_EMPTY: @@ -249,23 +287,21 @@ void ReProgramArgs::analyseLong(const char* opt) { value = ""; option->m_value = value; break; - case DT_BOOL: { - const char* boolValue = "f"; - if (value == NULL - || ReStringUtils::isInList(value, ";y;yes;t;true", true, + case DT_BOOL: + if (value == NULL){ + // Invert the default value: + option->m_value = option->m_defaultValue == "t" ? "f" : "t"; + } else if (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)) + option->m_value = "t"; + else if (ReStringUtils::isInList(value, ";n;no;f;false", + true, ReStringUtils::AUTO_SEPARATOR)) + option->m_value = "f"; + else 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; } @@ -304,18 +340,18 @@ bool ReProgramArgs::analyseShort(const char* opt, const char* nextArg) { case DT_STRING: case DT_STRING_EMPTY: if (opt[0] != '\0') { - setValue(opt->m_name, opt, option->m_type); + setValue(option->m_name, opt, option->m_type); } else { if (nextArg == NULL || nextArg[0] == '-') { - if (dataType[0] == DT_STRING_EMPTY) - setValue(nameStr, "", dataType); + if (option->m_type == DT_STRING_EMPTY) + setValue(option->m_name, "", option->m_type); else throw ReOptionException(this, - i18n( - "Option $1 has type $2! There is no parameter."), - nameStr, dataType); + QObject::tr( + "Option %1 has type %2! There is no parameter.") + .arg(option->m_name.constData()).arg(typeToString(option->m_type))); } else { - setValue(nameStr, nextArg, dataType); + setValue(option->m_name.constData(), nextArg, option->m_type); rc = true; } } @@ -329,9 +365,9 @@ bool ReProgramArgs::analyseShort(const char* opt, const char* nextArg) { } else if (opt[0] == '+') opt++; // Invert the default value: - if (properties.strOf(IxDefault)[0] == 't') + if (option->m_defaultValue == "t") value = value[0] == 't' ? "f" : "t"; - setValue(nameStr, value, dataType); + setValue(option->m_name, value, option->m_type); again = opt[0] != '\0'; break; } @@ -380,8 +416,8 @@ bool ReProgramArgs::getBool(const char* 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'; + .arg(typeToString(option->m_type))); + bool rc = option->m_value == "t"; return rc; } @@ -397,20 +433,20 @@ 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) + if (option->m_type != DT_INT) 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); + .arg(typeToString(option->m_type))); + int rc = atoi(option->m_value.constData()); return rc; } /** @brief Returns the value of a string option. * - * @param name Name of the option. + * @param name the name of the option * - * @return The value of the option set in the programs arguments or the default value. + * @return NULL: default value is NULL and no argument has been given
+ * the value of the option set in the programs arguments or the default value. * * @throws ReOptionException Unknown name or wrong type. */ @@ -421,10 +457,9 @@ const char* ReProgramArgs::getString(const char* name, QByteArray& buffer) { 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(); + .arg(typeToString(option->m_type))); + buffer = option->m_value; + return buffer == UNDEFINED_STRING ? NULL : buffer.constData(); } /** @@ -435,72 +470,67 @@ const char* ReProgramArgs::getString(const char* name, QByteArray& buffer) { * @param lines OUT: a stringlist for the help message */ void ReProgramArgs::help(const char* message, bool issueLastError, - ReStringList& lines) const { + QByteArrayList& lines) const { lines.append(m_usage); lines.append(""); - ReArrayPosition position; - if (m_properties.next(position, NULL, NULL)) { - lines.append(i18n(":")); + if (m_options.size() > 0) { + lines.append(QObject::tr(":").toUtf8()); } - 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) { + ReProgOptionMap::const_iterator it; + for (it = m_options.cbegin(); it != m_options.cend(); ++it){ + ReProgOption* opt = it.value(); + param.resize(0); + switch (opt->m_type) { case DT_INT: - param.append(i18n(""), -1); + param.append(QObject::tr("")); break; case DT_STRING: - param.append(i18n(""), -1); + param.append(QObject::tr("")); break; case DT_STRING_EMPTY: - param.append(i18n("[]"), -1); + param.append(QObject::tr("[]")); 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); + if (opt->m_shortName != HIDDEN_SHORT_NAME) { + line.append("-").append(opt->m_shortName); + line.append(param).append(' ').append(QObject::tr(" or ").toUtf8()); } - line.append(i18n("--"), -1).append(properties.strOf(IxLong), -1); + line.append("--").append(opt->m_longName); 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('\''); + if (opt->m_type != DT_STRING + || ! opt->m_defaultValue.isEmpty()) { + line.append(QObject::tr(" Default value: ").toUtf8()); + if (opt->m_type == DT_STRING) + line.append('\''); + line.append(opt->m_defaultValue); + if (opt->m_type == DT_STRING) + line.append('\''); } } lines.append(line.constData()); - line.set(PREFIX_LINE_OPTION, -1).append(properties.strOf(IxDescr), -1); + line.resize(0); + line.append(PREFIX_LINE_OPTION).append(opt->m_description); lines.append(line.constData()); } if (m_examples.count() > 0) { - lines.append(i18n("Example(s):")); + lines.append(QObject::tr("Example(s):").toUtf8()); lines.append(m_examples); } if (issueLastError && m_lastError.length() > 0) { - line.set("+++ ", 4).append(m_lastError.constData(), -1); + line.resize(0); + line.append("+++ ").append(m_lastError.constData()); lines.append(line.constData()); } if (message != NULL && message[0] != '\0') { - line.set("+++ ", 4).append(message, -1); + line.resize(0); + line.append("+++ ").append(message); lines.append(line.constData()); } } @@ -513,10 +543,10 @@ void ReProgramArgs::help(const char* message, bool issueLastError, */ void ReProgramArgs::help(const char* message, bool issueLastError, FILE* stream) const { - ReStringList lines(512, 1024, 8, 2); + QByteArrayList lines; help(message, issueLastError, lines); - for (size_t ii = 0; ii < lines.count(); ii++) { - fputs(lines.strOf(ii), stream); + for (int ii = 0; ii < lines.count(); ii++) { + fputs(lines.at(ii).constData(), stream); fputc('\n', stream); } } @@ -560,43 +590,31 @@ const char* ReProgramArgs::programName() const { /** @brief Search the property string of an option. * - * @param shortName The option`s short name. Not relevant if longName != NULL. - * @param LongName The option`s long name. Not relevant if longName == NULL. - * @param name Out: The name of the option. - * @param list Out: The properties are returned in this list. + * @param shortName the option`s short name. Not relevant if longName != NULL + * @param longName the option`s long name. Not relevant if longName == NULL + * @return the option * * @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; +ReProgOption* ReProgramArgs::search(char shortName, const char* longName) { + ReProgOptionMap::const_iterator it; + ReProgOption* rc = NULL; + ReProgOption* opt; + for (it = m_options.cbegin(); rc == NULL && it != m_options.cend(); ++it){ + opt = it.value(); + if ( (shortName != 0 && shortName == opt->m_shortName) + || longName == opt->m_longName) + rc = opt; } - if (!found) { + if (rc == NULL) { + QByteArray name; if (longName == NULL) - name.set(&shortName, 1); + name.append(shortName); else - name.set(longName, lengthLongName); - throw ReOptionException(this, i18n("Unknown option: $1"), name.constData()); + name = longName; + throw ReOptionException(this, QObject::tr("Unknown option: %1").arg(name.constData())); } + return rc; } /** @brief Sets the last error message. @@ -640,9 +658,7 @@ void ReProgramArgs::setValue(const char* name, const char* value, default: break; } - QByteArray buffer; - // First character says: defined. - buffer.appendChar(' ').append(value, -1); - m_values.put(name, buffer.constData()); + ReProgOption* opt = m_options.value(name); + opt->m_value = value; } diff --git a/base/ReProgramArgs.hpp b/base/ReProgramArgs.hpp index cdd6af8..ce5da5e 100644 --- a/base/ReProgramArgs.hpp +++ b/base/ReProgramArgs.hpp @@ -43,6 +43,7 @@ typedef QMap ReProgOptionMap; */ class ReProgramArgs { static const char* PREFIX_LINE_OPTION; + static QByteArray UNDEFINED_STRING; public: enum DataType { DT_UNDEF = 0, @@ -78,10 +79,10 @@ public: void setLastError(const char* message); void setLastError(const QByteArray& message); void setUsage(const char* usage[]); + const char* typeToString(DataType dataType); private: void addProperties(const char*name, const char* description, char shortOpt, - const char* longOpt, DataType dataType, const char* defaultValue, - size_t lengthValue); + const char* longOpt, DataType dataType, const char* defaultValue); void analyseLong(const char* opt); bool analyseShort(const char* opt, const char* nextArg); ReProgOption* search(char shortName, const char* longName); @@ -104,6 +105,7 @@ public: char m_shortName; QByteArray m_value; QByteArray m_defaultValue; + QByteArray m_description; }; #endif /* REPROGRAMARGS_H_ */ diff --git a/cunit/allTests.cpp b/cunit/allTests.cpp index de40ce2..e82c18a 100644 --- a/cunit/allTests.cpp +++ b/cunit/allTests.cpp @@ -30,6 +30,7 @@ static void testGui() { } static void testBase() { + void testReProgArgs(); void testReProcess(); void testReRandomizer(); void testReByteStorage(); @@ -43,6 +44,7 @@ static void testBase() { void testReWriter(); void testReFile(); void testReMatcher(); + testReProgArgs(); testReProcess(); testReRandomizer(); testReFileUtils(); diff --git a/cunit/cunit.pro b/cunit/cunit.pro index a3195c8..181449c 100644 --- a/cunit/cunit.pro +++ b/cunit/cunit.pro @@ -17,6 +17,7 @@ INCLUDEPATH = .. SOURCES += main.cpp \ cuReLexer.cpp \ + cuReProgArgs.cpp \ cuReFileSystem.cpp \ cuReCryptFileSystem.cpp \ cuReRandomizer.cpp \ @@ -59,7 +60,7 @@ SOURCES += main.cpp \ allTests.cpp \ ../base/ReProcess.cpp \ cuReProcess.cpp \ - ../base/ReProgramArgs.cpp + ../base/ReProgramArgs.cpp HEADERS += \ ../base/ReFile.hpp \