From 8896fb7673a8405fa5d072a00762f066944895f6 Mon Sep 17 00:00:00 2001 From: Martchus Date: Mon, 27 Jul 2015 23:19:10 +0200 Subject: [PATCH] added missing initialization of m_denotesOperation, small adjustments --- application/argumentparser.cpp | 121 ++++++++++++++++++++++----------- application/argumentparser.h | 16 +++-- 2 files changed, 89 insertions(+), 48 deletions(-) diff --git a/application/argumentparser.cpp b/application/argumentparser.cpp index c514755..539bb06 100644 --- a/application/argumentparser.cpp +++ b/application/argumentparser.cpp @@ -59,6 +59,7 @@ Argument::Argument(const char *name, const char *abbreviation, const char *descr m_required(false), m_combinable(false), m_implicit(false), + m_denotesOperation(false), m_requiredValueCount(0), m_default(false), m_present(false), @@ -168,14 +169,15 @@ Argument *firstPresentUncombinableArg(const ArgumentVector &args, const Argument /*! * Sets the secondary arguments for this arguments. The given arguments will be considered as - * secondary arguments of this argument by the ArgumentParser. This means that the parser - * will complain if these arguments are given, but not their parent. If secondary arguments are + * secondary arguments of this argument by the argument parser. This means that the parser + * will complain if these arguments are given, but not this argument. If secondary arguments are * labeled as mandatory their parent is also mandatory. * * The Argument does not take ownership. Do not destroy the given arguments as long as they are * used as secondary arguments. * * \sa secondaryArguments() + * \sa addSecondaryArgument() * \sa hasSecondaryArguments() */ void Argument::setSecondaryArguments(const ArgumentInitializerList &secondaryArguments) @@ -195,6 +197,23 @@ void Argument::setSecondaryArguments(const ArgumentInitializerList &secondaryArg } } +/*! + * Adds \a arg as a secondary argument for this argument. + * + * \sa secondaryArguments() + * \sa setSecondaryArguments() + * \sa hasSecondaryArguments() + */ +void Argument::addSecondaryArgument(Argument *arg) +{ + if(find(m_secondaryArgs.cbegin(), m_secondaryArgs.cend(), arg) == m_secondaryArgs.cend()) { + m_secondaryArgs.push_back(arg); + if(find(arg->m_parents.cbegin(), arg->m_parents.cend(), this) == arg->m_parents.cend()) { + arg->m_parents.push_back(this); + } + } +} + /*! * Returns the names of the parents in the form "parent1", "parent2, "parent3", ... * Returns an empty string if this Argument has no parents. @@ -338,19 +357,32 @@ void ArgumentParser::verifySetup() const vector verifiedArgs; vector abbreviations; vector names; + const Argument *implicitArg = nullptr; function checkArguments; - checkArguments = [&verifiedArgs, &abbreviations, &names, &checkArguments, this] (const ArgumentVector &args) { + checkArguments = [&verifiedArgs, &abbreviations, &names, &checkArguments, &implicitArg, this] (const ArgumentVector &args) { for(Argument *arg : args) { - if(find(verifiedArgs.cbegin(), verifiedArgs.cend(), arg) != verifiedArgs.cend()) + if(find(verifiedArgs.cbegin(), verifiedArgs.cend(), arg) != verifiedArgs.cend()) { continue; // do not verify the same argument twice - if(arg->isMainArgument() && arg->parents().size()) + } + if(arg->isMainArgument() && arg->parents().size()) { throw invalid_argument("Argument \"" + arg->name() + "\" can not be used as main argument and sub argument at the same time."); - if(!arg->abbreviation().empty() && find(abbreviations.cbegin(), abbreviations.cend(), arg->abbreviation()) != abbreviations.cend()) + } + if(!arg->abbreviation().empty() && find(abbreviations.cbegin(), abbreviations.cend(), arg->abbreviation()) != abbreviations.cend()) { throw invalid_argument("Abbreviation \"" + arg->abbreviation() + "\" has been used more then once."); - if(find(names.cbegin(), names.cend(), arg->name()) != names.cend()) + } + if(find(names.cbegin(), names.cend(), arg->name()) != names.cend()) { throw invalid_argument("Name \"" + arg->name() + "\" has been used more then once."); - if(arg->isDefault() && arg->requiredValueCount() > 0 && arg->defaultValues().size() < static_cast(arg->requiredValueCount())) + } + if(arg->isDefault() && arg->requiredValueCount() > 0 && arg->defaultValues().size() < static_cast(arg->requiredValueCount())) { throw invalid_argument("Default argument \"" + arg->name() + "\" doesn't provide the required number of default values."); + } + if(arg->isImplicit()) { + if(implicitArg) { + throw invalid_argument("The arguments \"" + implicitArg->name() + "\" and \"" + arg->name() + "\" can not be both implicit."); + } else { + implicitArg = arg; + } + } abbreviations.push_back(arg->abbreviation()); names.push_back(arg->name()); verifiedArgs.push_back(arg); @@ -386,11 +418,19 @@ void ArgumentParser::parseArgs(int argc, char *argv[]) } else { m_currentDirectory.clear(); } + // function for iterating through all arguments + function &)> foreachArg; + foreachArg = [&foreachArg] (Argument *parent, const ArgumentVector &args, const function &proc) { + for(Argument *arg : args) { + proc(parent, arg); + foreachArg(arg, arg->secondaryArguments(), proc); + } + }; // parse given arguments if(argc >= 2) { Argument *currentArg = nullptr; // iterate through given arguments - for(char **i = argv + 1, ** end = argv + argc; i != end; ++i) { + for(char **i = argv + 1, **end = argv + argc; i != end; ++i) { string givenArg(*i); // convert argument to string if(!givenArg.empty()) { // skip empty entries if(valuesToRead <= 0 && givenArg.size() > 1 && givenArg.front() == '-') { @@ -414,13 +454,13 @@ void ArgumentParser::parseArgs(int argc, char *argv[]) return arg->abbreviation() == givenId; }; } - // find the corresponding instande of the Argument class + // find the corresponding instance of the Argument class currentArg = findArg(pred); if(currentArg) { // the corresponding instance of Argument class has been found if(currentArg->m_present) { // the argument has been provided more then once - throw Failure("The argument \"" + currentArg->name() + "\" has been given more then one time."); + throw Failure("The argument \"" + currentArg->name() + "\" has been specified more than one time."); } else { // set present flag of argument currentArg->m_present = true; @@ -464,6 +504,7 @@ void ArgumentParser::parseArgs(int argc, char *argv[]) } } if(currentArg) { + cout << "first arg found" << endl; currentArg->m_present = true; ++actualArgc; // we actually found an argument // now we might need to read values tied to that argument @@ -472,16 +513,19 @@ void ArgumentParser::parseArgs(int argc, char *argv[]) } } // -> check if there's an implicit argument definition - for(Argument *arg : m_mainArgs) { - if(!arg->isPresent() && arg->isImplicit()) { - // set present flag of argument - arg->m_present = true; - ++actualArgc; // we actually found an argument - // now we might need to read values tied to that argument - valuesToRead = arg->requiredValueCount(); - currentArg = arg; - break; - } + try { + foreachArg(nullptr, m_mainArgs, [&actualArgc, &valuesToRead, ¤tArg, this] (Argument *, Argument *arg) { + if(!arg->isPresent() && arg->isImplicit()) { + throw arg; + } + }); + } catch(Argument *arg) { + // set present flag of argument + arg->m_present = true; + ++actualArgc; // we actually found an argument + // now we might need to read values tied to that argument + valuesToRead = arg->requiredValueCount(); + currentArg = arg; } } if(currentArg) { @@ -509,16 +553,23 @@ void ArgumentParser::parseArgs(int argc, char *argv[]) } } } - // function for iterating through all arguments - function &)> foreachArg; - foreachArg = [&foreachArg] (Argument *parent, const ArgumentVector &args, const function &proc) { - for(Argument *arg : args) { - proc(parent, arg); - foreachArg(arg, arg->secondaryArguments(), proc); - } - }; // iterate actually through all arguments using previously defined function to check gathered arguments foreachArg(nullptr, m_mainArgs, [this] (Argument *parent, Argument *arg) { + if(!arg->isPresent()) { + // the argument might be flagged as present if its a default argument + if(arg->isDefault() && (arg->isMainArgument() || (parent && parent->isPresent()))) { + arg->m_present = true; + if(firstPresentUncombinableArg(arg->isMainArgument() ? m_mainArgs : parent->secondaryArguments(), arg)) { + arg->m_present = false; + } + } + // throw an error if mandatory argument is not present + if(!arg->isPresent() && (arg->isRequired() && (arg->isMainArgument() || (parent && parent->isPresent())))) { + throw Failure("The argument \"" + arg->name() + "\" is required but not given."); + } + } + }); + foreachArg(nullptr, m_mainArgs, [this] (Argument *, Argument *arg) { if(arg->isPresent()) { if(!arg->isMainArgument() && arg->parents().size() && !arg->isParentPresent()) { if(arg->parents().size() > 1) { @@ -551,18 +602,6 @@ void ArgumentParser::parseArgs(int argc, char *argv[]) } throw Failure(ss.str()); } - } else { // argument not present - // the argument might be flagged as present if its a default argument - if(arg->isDefault() && (arg->isMainArgument() || (parent && parent->isPresent()))) { - arg->m_present = true; - if(firstPresentUncombinableArg(arg->isMainArgument() ? m_mainArgs : parent->secondaryArguments(), arg)) { - arg->m_present = false; - } - } - // throw an error if mandatory argument is not present - if(!arg->isPresent() && (arg->isRequired() && (arg->isMainArgument() || (parent && parent->isPresent())))) { - throw Failure("The argument \"" + arg->name() + "\" is required but not given."); - } } }); // set actual argument count diff --git a/application/argumentparser.h b/application/argumentparser.h index 69700c6..8a6df89 100644 --- a/application/argumentparser.h +++ b/application/argumentparser.h @@ -69,6 +69,7 @@ public: void printInfo(std::ostream &os, unsigned char indentionLevel = 0) const; const ArgumentVector &secondaryArguments() const; void setSecondaryArguments(const ArgumentInitializerList &secondaryArguments); + void addSecondaryArgument(Argument *arg); bool hasSecondaryArguments() const; const ArgumentVector parents() const; bool isMainArgument() const; @@ -174,7 +175,7 @@ inline void Argument::setDescription(const std::string &description) /*! * \brief Returns the additional values for the argument. * - * These values set by the parser when the command line arguments. + * These values set by the parser when parsing the command line arguments. */ inline const StringVector &Argument::values() const { @@ -184,7 +185,7 @@ inline const StringVector &Argument::values() const /*! * \brief Returns the value with the give \a index. * - * These values set by the parser when the command line arguments. + * These values set by the parser when parsing the command line arguments. */ inline const std::string &Argument::value(StringVector::size_type index) const { @@ -262,7 +263,7 @@ inline const StringList &Argument::valueNames() const */ inline void Argument::setValueNames(std::initializer_list valueNames) { - m_valueNames = std::list(valueNames); + m_valueNames.assign(valueNames); } /*! @@ -302,9 +303,9 @@ inline bool Argument::allRequiredValuesPresent() const /*! * \brief Returns an indication whether the argument is a default argument. * - * A default argument will be flagged as present when parsing arguments event - * if it is not actually present if there is no uncombinable argument present - * and it is a main argument or the parent is present. + * A default argument will be flagged as present when parsing arguments even + * if it is not actually present and there is no uncombinable argument present + * and the it is a main argument or the parent is present. * * The callback function will be invoked in this case as the argument where * actually present. @@ -418,7 +419,8 @@ inline void Argument::setCombinable(bool value) /*! * \brief Returns an indication whether the argument can be specified implicitely. * - * An implicit main argument is assumed to be present even if only its value is present. + * An implicit argument is assumed to be present even if only its value is present. + * Only one argument can be implicit. * * \sa setImplicit() */