Check for siblings of parent args
This commit is contained in:
parent
a3648963ee
commit
8bcf8cd008
|
@ -35,6 +35,15 @@ inline bool notEmpty(const char *str)
|
||||||
|
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The ArgumentDenotationType enum specifies the type of a given argument denotation.
|
||||||
|
*/
|
||||||
|
enum ArgumentDenotationType : unsigned char {
|
||||||
|
Value = 0, /**< parameter value */
|
||||||
|
Abbreviation = 1, /**< argument abbreviation */
|
||||||
|
FullName = 2 /**< full argument name */
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \class ApplicationUtilities::Argument
|
* \class ApplicationUtilities::Argument
|
||||||
* \brief The Argument class is a wrapper for command line argument information.
|
* \brief The Argument class is a wrapper for command line argument information.
|
||||||
|
@ -372,7 +381,9 @@ void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
||||||
if(--argc) {
|
if(--argc) {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
++argv;
|
++argv;
|
||||||
readSpecifiedArgs(m_mainArgs, index, argv, argv + argc);
|
vector<Argument *> path;
|
||||||
|
path.reserve(4);
|
||||||
|
readSpecifiedArgs(m_mainArgs, index, argv, argv + argc, path);
|
||||||
} else {
|
} else {
|
||||||
// no arguments specified -> set default argument as present
|
// no arguments specified -> set default argument as present
|
||||||
if(m_defaultArg) {
|
if(m_defaultArg) {
|
||||||
|
@ -431,14 +442,8 @@ void ApplicationUtilities::ArgumentParser::verifyArgs(const ArgumentVector &args
|
||||||
* \brief Reads the specified commands line arguments.
|
* \brief Reads the specified commands line arguments.
|
||||||
* \remarks Results are stored in Argument instances added as main arguments and sub arguments.
|
* \remarks Results are stored in Argument instances added as main arguments and sub arguments.
|
||||||
*/
|
*/
|
||||||
void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index, const char *const *&argv, const char *const *end, unsigned int level)
|
void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index, const char *const *&argv, const char *const *end, std::vector<Argument *> ¤tPath)
|
||||||
{
|
{
|
||||||
enum ArgumentDenotationType : unsigned char {
|
|
||||||
Value = 0, // parameter value
|
|
||||||
Abbreviation = 1, // argument abbreviation
|
|
||||||
FullName = 2 // full argument name
|
|
||||||
};
|
|
||||||
|
|
||||||
Argument *lastArg = nullptr;
|
Argument *lastArg = nullptr;
|
||||||
vector<const char *> *values = nullptr;
|
vector<const char *> *values = nullptr;
|
||||||
while(argv != end) {
|
while(argv != end) {
|
||||||
|
@ -456,9 +461,10 @@ void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index,
|
||||||
|
|
||||||
// try to find matching Argument instance
|
// try to find matching Argument instance
|
||||||
Argument *matchingArg = nullptr;
|
Argument *matchingArg = nullptr;
|
||||||
|
size_t argDenLen;
|
||||||
if(argDenotationType != Value) {
|
if(argDenotationType != Value) {
|
||||||
const char *const equationPos = strchr(argDenotation, '=');
|
const char *const equationPos = strchr(argDenotation, '=');
|
||||||
for(const auto argDenLen = equationPos ? static_cast<size_t>(equationPos - argDenotation) : strlen(argDenotation); ; matchingArg = nullptr) {
|
for(argDenLen = equationPos ? static_cast<size_t>(equationPos - argDenotation) : strlen(argDenotation); ; matchingArg = nullptr) {
|
||||||
// search for arguments by abbreviation or name depending on the denotation type
|
// search for arguments by abbreviation or name depending on the denotation type
|
||||||
if(argDenotationType == Abbreviation) {
|
if(argDenotationType == Abbreviation) {
|
||||||
for(Argument *arg : args) {
|
for(Argument *arg : args) {
|
||||||
|
@ -491,7 +497,9 @@ void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index,
|
||||||
// read sub arguments if no abbreviated argument follows
|
// read sub arguments if no abbreviated argument follows
|
||||||
++index, ++m_actualArgc, lastArg = matchingArg;
|
++index, ++m_actualArgc, lastArg = matchingArg;
|
||||||
if(argDenotationType != Abbreviation || (!*++argDenotation && argDenotation != equationPos)) {
|
if(argDenotationType != Abbreviation || (!*++argDenotation && argDenotation != equationPos)) {
|
||||||
readSpecifiedArgs(matchingArg->m_subArgs, index, ++argv, end, level + 1);
|
currentPath.push_back(matchingArg);
|
||||||
|
readSpecifiedArgs(matchingArg->m_subArgs, index, ++argv, end, currentPath);
|
||||||
|
currentPath.pop_back();
|
||||||
break;
|
break;
|
||||||
} // else: another abbreviated argument follows
|
} // else: another abbreviated argument follows
|
||||||
} else {
|
} else {
|
||||||
|
@ -501,14 +509,29 @@ void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index,
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!matchingArg) {
|
if(!matchingArg) {
|
||||||
|
if(argDenotationType != Value) {
|
||||||
|
// unknown argument might be a sibling of the parent element
|
||||||
|
for(auto parentArgument = currentPath.crbegin(), end = currentPath.crend(); parentArgument != end; ) {
|
||||||
|
for(Argument *sibling : (++parentArgument != end ? (*parentArgument)->subArguments() : m_mainArgs)) {
|
||||||
|
if(sibling->occurrences() < sibling->maxOccurrences()) {
|
||||||
|
if((argDenotationType == Abbreviation && (sibling->abbreviation() && sibling->abbreviation() == *argDenotation))
|
||||||
|
|| (sibling->name() && !strncmp(sibling->name(), argDenotation, argDenLen))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(lastArg && values->size() < lastArg->requiredValueCount()) {
|
if(lastArg && values->size() < lastArg->requiredValueCount()) {
|
||||||
// treat unknown argument as parameter of last argument
|
// unknown argument might just be a parameter of the last argument
|
||||||
values->emplace_back(abbreviationFound ? argDenotation : *argv);
|
values->emplace_back(abbreviationFound ? argDenotation : *argv);
|
||||||
++index, ++argv;
|
++index, ++argv;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
// first value might denote "operation"
|
// first value might denote "operation"
|
||||||
if(!level) {
|
if(currentPath.empty()) {
|
||||||
for(Argument *arg : args) {
|
for(Argument *arg : args) {
|
||||||
if(arg->denotesOperation() && arg->name() && !strcmp(arg->name(), *argv)) {
|
if(arg->denotesOperation() && arg->name() && !strcmp(arg->name(), *argv)) {
|
||||||
(matchingArg = arg)->m_indices.push_back(index);
|
(matchingArg = arg)->m_indices.push_back(index);
|
||||||
|
@ -519,7 +542,7 @@ void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index,
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!matchingArg) {
|
if(!matchingArg) {
|
||||||
// use the first default argument
|
// use the first default argument which is not already present
|
||||||
for(Argument *arg : args) {
|
for(Argument *arg : args) {
|
||||||
if(arg->isImplicit() && !arg->isPresent()) {
|
if(arg->isImplicit() && !arg->isPresent()) {
|
||||||
(matchingArg = arg)->m_indices.push_back(index);
|
(matchingArg = arg)->m_indices.push_back(index);
|
||||||
|
@ -527,6 +550,7 @@ void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(matchingArg) {
|
if(matchingArg) {
|
||||||
// an argument matched the specified denotation
|
// an argument matched the specified denotation
|
||||||
if(lastArg == matchingArg) {
|
if(lastArg == matchingArg) {
|
||||||
|
@ -537,13 +561,15 @@ void ArgumentParser::readSpecifiedArgs(ArgumentVector &args, std::size_t &index,
|
||||||
matchingArg->m_values.emplace_back();
|
matchingArg->m_values.emplace_back();
|
||||||
values = &matchingArg->m_values.back();
|
values = &matchingArg->m_values.back();
|
||||||
|
|
||||||
// read sub arguments if no abbreviated argument follows
|
// read sub arguments
|
||||||
++m_actualArgc, lastArg = matchingArg;
|
++m_actualArgc, lastArg = matchingArg;
|
||||||
readSpecifiedArgs(matchingArg->m_subArgs, index, argv, end, level + 1);
|
currentPath.push_back(matchingArg);
|
||||||
|
readSpecifiedArgs(matchingArg->m_subArgs, index, argv, end, currentPath);
|
||||||
|
currentPath.pop_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(!level) {
|
if(currentPath.empty()) {
|
||||||
if(m_ignoreUnknownArgs) {
|
if(m_ignoreUnknownArgs) {
|
||||||
cerr << "The specified argument \"" << *argv << "\" is unknown and will be ignored." << endl;
|
cerr << "The specified argument \"" << *argv << "\" is unknown and will be ignored." << endl;
|
||||||
++index, ++argv;
|
++index, ++argv;
|
||||||
|
|
|
@ -529,7 +529,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args);)
|
IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args);)
|
||||||
void readSpecifiedArgs(ArgumentVector &args, std::size_t &index, const char *const *&argv, const char *const *end, unsigned int level = 0);
|
void readSpecifiedArgs(ArgumentVector &args, std::size_t &index, const char *const *&argv, const char *const *end, std::vector<Argument *> ¤tPath);
|
||||||
void checkConstraints(const ArgumentVector &args);
|
void checkConstraints(const ArgumentVector &args);
|
||||||
void invokeCallbacks(const ArgumentVector &args);
|
void invokeCallbacks(const ArgumentVector &args);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue