Use C-strings for argument definitions
Argument names and abbreviations are always C-string literals and hence using std::string has no advantage.
This commit is contained in:
parent
2a58a83c3c
commit
f3077ef8e3
|
@ -25,6 +25,11 @@ const char *applicationAuthor = nullptr;
|
||||||
const char *applicationVersion = nullptr;
|
const char *applicationVersion = nullptr;
|
||||||
const char *applicationUrl = nullptr;
|
const char *applicationUrl = nullptr;
|
||||||
|
|
||||||
|
inline bool notEmpty(const char *str)
|
||||||
|
{
|
||||||
|
return str && *str;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \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.
|
||||||
|
@ -41,7 +46,11 @@ const char *applicationUrl = nullptr;
|
||||||
* The \a name and the abbreviation mustn't contain any whitespaces.
|
* The \a name and the abbreviation mustn't contain any whitespaces.
|
||||||
* The \a name mustn't be empty. The \a abbreviation and the \a description might be empty.
|
* The \a name mustn't be empty. The \a abbreviation and the \a description might be empty.
|
||||||
*/
|
*/
|
||||||
Argument::Argument(const std::string &name, const std::string abbreviation, const std::string &description) :
|
Argument::Argument(const char *name, const char *abbreviation, const char *description, const char *example) :
|
||||||
|
m_name(name),
|
||||||
|
m_abbreviation(abbreviation),
|
||||||
|
m_description(description),
|
||||||
|
m_example(example),
|
||||||
m_required(false),
|
m_required(false),
|
||||||
m_combinable(false),
|
m_combinable(false),
|
||||||
m_implicit(false),
|
m_implicit(false),
|
||||||
|
@ -50,40 +59,7 @@ Argument::Argument(const std::string &name, const std::string abbreviation, cons
|
||||||
m_default(false),
|
m_default(false),
|
||||||
m_present(false),
|
m_present(false),
|
||||||
m_isMainArg(false)
|
m_isMainArg(false)
|
||||||
{
|
{}
|
||||||
setName(name);
|
|
||||||
setAbbreviation(abbreviation);
|
|
||||||
setDescription(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Constructs an Argument with the given \a name, \a abbreviation and \a description.
|
|
||||||
*
|
|
||||||
* The \a name and the abbreviation mustn't contain any whitespaces.
|
|
||||||
* The \a name mustn't be empty. The \a abbreviation and the \a description might be empty.
|
|
||||||
*/
|
|
||||||
Argument::Argument(const char *name, const char *abbreviation, const char *description) :
|
|
||||||
m_required(false),
|
|
||||||
m_combinable(false),
|
|
||||||
m_implicit(false),
|
|
||||||
m_denotesOperation(false),
|
|
||||||
m_requiredValueCount(0),
|
|
||||||
m_default(false),
|
|
||||||
m_present(false),
|
|
||||||
m_isMainArg(false)
|
|
||||||
{
|
|
||||||
if(name) {
|
|
||||||
setName(name);
|
|
||||||
} else {
|
|
||||||
setName(string());
|
|
||||||
}
|
|
||||||
if(abbreviation) {
|
|
||||||
setAbbreviation(abbreviation);
|
|
||||||
}
|
|
||||||
if(description) {
|
|
||||||
setDescription(description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Destroys the Argument.
|
* \brief Destroys the Argument.
|
||||||
|
@ -126,13 +102,13 @@ Argument::~Argument()
|
||||||
void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
||||||
{
|
{
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
||||||
if(!name().empty()) {
|
if(notEmpty(name())) {
|
||||||
os << "--" << name();
|
os << "--" << name();
|
||||||
}
|
}
|
||||||
if(!name().empty() && !abbreviation().empty()) {
|
if(notEmpty(name()) && notEmpty(abbreviation())) {
|
||||||
os << ", ";
|
os << ", ";
|
||||||
}
|
}
|
||||||
if(!abbreviation().empty()) {
|
if(notEmpty(abbreviation())) {
|
||||||
os << "-" << abbreviation();
|
os << "-" << abbreviation();
|
||||||
}
|
}
|
||||||
if(requiredValueCount() > 0) {
|
if(requiredValueCount() > 0) {
|
||||||
|
@ -151,7 +127,7 @@ void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
||||||
os << " ...";
|
os << " ...";
|
||||||
}
|
}
|
||||||
++indentionLevel;
|
++indentionLevel;
|
||||||
if(!description().empty()) {
|
if(notEmpty(description())) {
|
||||||
os << endl;
|
os << endl;
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
||||||
os << description();
|
os << description();
|
||||||
|
@ -161,7 +137,7 @@ void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
||||||
os << "This argument is required.";
|
os << "This argument is required.";
|
||||||
}
|
}
|
||||||
if(!example().empty()) {
|
if(notEmpty(example())) {
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
for(unsigned char i = 0; i < indentionLevel; ++i) os << " ";
|
||||||
os << endl << "Usage: " << example();
|
os << endl << "Usage: " << example();
|
||||||
}
|
}
|
||||||
|
@ -391,6 +367,7 @@ Argument *ArgumentParser::findArg(const ArgumentVector &arguments, const Argumen
|
||||||
return nullptr; // no argument matches
|
return nullptr; // no argument matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_BUILD
|
||||||
/*!
|
/*!
|
||||||
* \brief This method is used to verify the setup of the command line parser before parsing.
|
* \brief This method is used to verify the setup of the command line parser before parsing.
|
||||||
*
|
*
|
||||||
|
@ -416,32 +393,37 @@ void ArgumentParser::verifySetup() const
|
||||||
continue; // do not verify the same argument twice
|
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.");
|
throw invalid_argument("Argument \"" + string(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(notEmpty(arg->abbreviation()) && find(abbreviations.cbegin(), abbreviations.cend(), arg->abbreviation()) != abbreviations.cend()) {
|
||||||
throw invalid_argument("Abbreviation \"" + arg->abbreviation() + "\" has been used more then once.");
|
throw invalid_argument("Abbreviation \"" + string(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.");
|
throw invalid_argument("Name \"" + string(arg->name()) + "\" has been used more then once.");
|
||||||
}
|
}
|
||||||
if(arg->isDefault() && arg->requiredValueCount() > 0 && arg->defaultValues().size() < static_cast<size_t>(arg->requiredValueCount())) {
|
if(arg->isDefault() && arg->requiredValueCount() > 0 && arg->defaultValues().size() < static_cast<size_t>(arg->requiredValueCount())) {
|
||||||
throw invalid_argument("Default argument \"" + arg->name() + "\" doesn't provide the required number of default values.");
|
throw invalid_argument("Default argument \"" + string(arg->name()) + "\" doesn't provide the required number of default values.");
|
||||||
}
|
}
|
||||||
if(arg->isImplicit()) {
|
if(arg->isImplicit()) {
|
||||||
if(implicitArg) {
|
if(implicitArg) {
|
||||||
throw invalid_argument("The arguments \"" + implicitArg->name() + "\" and \"" + arg->name() + "\" can not be both implicit.");
|
throw invalid_argument("The arguments \"" + string(implicitArg->name()) + "\" and \"" + string(arg->name()) + "\" can not be both implicit.");
|
||||||
} else {
|
} else {
|
||||||
implicitArg = arg;
|
implicitArg = arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
abbreviations.push_back(arg->abbreviation());
|
if(arg->abbreviation()) {
|
||||||
names.push_back(arg->name());
|
abbreviations.push_back(arg->abbreviation());
|
||||||
|
}
|
||||||
|
if(arg->name()) {
|
||||||
|
names.push_back(arg->name());
|
||||||
|
}
|
||||||
verifiedArgs.push_back(arg);
|
verifiedArgs.push_back(arg);
|
||||||
checkArguments(arg->secondaryArguments());
|
checkArguments(arg->secondaryArguments());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
checkArguments(m_mainArgs);
|
checkArguments(m_mainArgs);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This method invokes verifySetup() before parsing. See its do documentation for more
|
* \brief This method invokes verifySetup() before parsing. See its do documentation for more
|
||||||
|
@ -459,7 +441,9 @@ void ArgumentParser::verifySetup() const
|
||||||
void ArgumentParser::parseArgs(int argc, char *argv[])
|
void ArgumentParser::parseArgs(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// initiate parser
|
// initiate parser
|
||||||
|
#ifdef DEBUG_BUILD
|
||||||
verifySetup();
|
verifySetup();
|
||||||
|
#endif
|
||||||
m_actualArgc = 0; // reset actual agument count
|
m_actualArgc = 0; // reset actual agument count
|
||||||
unsigned int actualArgc = 0;
|
unsigned int actualArgc = 0;
|
||||||
int valuesToRead = 0;
|
int valuesToRead = 0;
|
||||||
|
@ -511,7 +495,7 @@ void ArgumentParser::parseArgs(int argc, char *argv[])
|
||||||
// the corresponding instance of Argument class has been found
|
// the corresponding instance of Argument class has been found
|
||||||
if(currentArg->m_present) {
|
if(currentArg->m_present) {
|
||||||
// the argument has been provided more then once
|
// the argument has been provided more then once
|
||||||
throw Failure("The argument \"" + currentArg->name() + "\" has been specified more than one time.");
|
throw Failure("The argument \"" + string(currentArg->name()) + "\" has been specified more than one time.");
|
||||||
} else {
|
} else {
|
||||||
// set present flag of argument
|
// set present flag of argument
|
||||||
currentArg->m_present = true;
|
currentArg->m_present = true;
|
||||||
|
@ -615,7 +599,7 @@ void ArgumentParser::parseArgs(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
// throw an error if mandatory argument is not present
|
// throw an error if mandatory argument is not present
|
||||||
if(!arg->isPresent() && (arg->isRequired() && (arg->isMainArgument() || (parent && parent->isPresent())))) {
|
if(!arg->isPresent() && (arg->isRequired() && (arg->isMainArgument() || (parent && parent->isPresent())))) {
|
||||||
throw Failure("The argument \"" + arg->name() + "\" is required but not given.");
|
throw Failure("The argument \"" + string(arg->name()) + "\" is required but not given.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -623,9 +607,9 @@ void ArgumentParser::parseArgs(int argc, char *argv[])
|
||||||
if(arg->isPresent()) {
|
if(arg->isPresent()) {
|
||||||
if(!arg->isMainArgument() && arg->parents().size() && !arg->isParentPresent()) {
|
if(!arg->isMainArgument() && arg->parents().size() && !arg->isParentPresent()) {
|
||||||
if(arg->parents().size() > 1) {
|
if(arg->parents().size() > 1) {
|
||||||
throw Failure("The argument \"" + arg->name() + "\" needs to be used together with one the following arguments: " + arg->parentNames());
|
throw Failure("The argument \"" + string(arg->name()) + "\" needs to be used together with one the following arguments: " + arg->parentNames());
|
||||||
} else {
|
} else {
|
||||||
throw Failure("The argument \"" + arg->name() + "\" needs to be used together with the argument \"" + arg->parents().front()->name() + "\".");
|
throw Failure("The argument \"" + string(arg->name()) + "\" needs to be used together with the argument \"" + arg->parents().front()->name() + "\".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Argument *conflictingArgument = nullptr;
|
Argument *conflictingArgument = nullptr;
|
||||||
|
@ -637,11 +621,11 @@ void ArgumentParser::parseArgs(int argc, char *argv[])
|
||||||
conflictingArgument = arg->conflictsWithArgument();
|
conflictingArgument = arg->conflictsWithArgument();
|
||||||
}
|
}
|
||||||
if(conflictingArgument) {
|
if(conflictingArgument) {
|
||||||
throw Failure("The argument \"" + conflictingArgument->name() + "\" can not be combined with \"" + arg->name() + "\".");
|
throw Failure("The argument \"" + string(conflictingArgument->name()) + "\" can not be combined with \"" + arg->name() + "\".");
|
||||||
}
|
}
|
||||||
if(!arg->allRequiredValuesPresent()) {
|
if(!arg->allRequiredValuesPresent()) {
|
||||||
stringstream ss(stringstream::in | stringstream::out);
|
stringstream ss(stringstream::in | stringstream::out);
|
||||||
ss << "Not all required information for the given argument \"" << arg->name() << "\" provided. You have to give the following information:";
|
ss << "Not all required information for the given argument \"" << string(arg->name()) << "\" provided. You have to give the following information:";
|
||||||
int valueNamesPrint = 0;
|
int valueNamesPrint = 0;
|
||||||
for(const auto &name : arg->m_valueNames) {
|
for(const auto &name : arg->m_valueNames) {
|
||||||
ss << "\n" << name;
|
ss << "\n" << name;
|
||||||
|
|
|
@ -41,19 +41,18 @@ class LIB_EXPORT Argument
|
||||||
public:
|
public:
|
||||||
typedef std::function <void (const StringVector &)> CallbackFunction;
|
typedef std::function <void (const StringVector &)> CallbackFunction;
|
||||||
|
|
||||||
Argument(const std::string &name, const std::string abbreviation = std::string(), const std::string &description = std::string());
|
Argument(const char *name, const char *abbreviation = nullptr, const char *description = nullptr, const char *example = nullptr);
|
||||||
Argument(const char *name, const char *abbreviation = nullptr, const char *description = nullptr);
|
|
||||||
~Argument();
|
~Argument();
|
||||||
|
|
||||||
const std::string &name() const;
|
const char *name() const;
|
||||||
void setName(const std::string &name);
|
void setName(const char *name);
|
||||||
const std::string &abbreviation() const;
|
const char *abbreviation() const;
|
||||||
void setAbbreviation(const std::string &abbreviation);
|
void setAbbreviation(const char *abbreviation);
|
||||||
//unsigned char isAmbiguous(const ArgumentParser &parser) const;
|
//unsigned char isAmbiguous(const ArgumentParser &parser) const;
|
||||||
const std::string &description() const;
|
const char *description() const;
|
||||||
void setDescription(const std::string &description);
|
void setDescription(const char *description);
|
||||||
const std::string &example() const;
|
const char *example() const;
|
||||||
void setExample(const std::string &example);
|
void setExample(const char *example);
|
||||||
const StringVector &values() const;
|
const StringVector &values() const;
|
||||||
const std::string &value(StringVector::size_type index) const;
|
const std::string &value(StringVector::size_type index) const;
|
||||||
StringVector::size_type valueCount() const;
|
StringVector::size_type valueCount() const;
|
||||||
|
@ -90,10 +89,10 @@ public:
|
||||||
Argument *conflictsWithArgument() const;
|
Argument *conflictsWithArgument() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
const char *m_name;
|
||||||
std::string m_abbreviation;
|
const char *m_abbreviation;
|
||||||
std::string m_description;
|
const char *m_description;
|
||||||
std::string m_example;
|
const char *m_example;
|
||||||
bool m_required;
|
bool m_required;
|
||||||
bool m_combinable;
|
bool m_combinable;
|
||||||
bool m_implicit;
|
bool m_implicit;
|
||||||
|
@ -116,7 +115,7 @@ private:
|
||||||
* The parser compares the name with the characters following a "--" prefix to
|
* The parser compares the name with the characters following a "--" prefix to
|
||||||
* identify arguments.
|
* identify arguments.
|
||||||
*/
|
*/
|
||||||
inline const std::string &Argument::name() const
|
inline const char *Argument::name() const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
@ -129,11 +128,20 @@ inline const std::string &Argument::name() const
|
||||||
* The parser compares the name with the characters following a "--" prefix to
|
* The parser compares the name with the characters following a "--" prefix to
|
||||||
* identify arguments.
|
* identify arguments.
|
||||||
*/
|
*/
|
||||||
inline void Argument::setName(const std::string &name)
|
inline void Argument::setName(const char *name)
|
||||||
{
|
{
|
||||||
if(name.empty() || name.find(' ') != std::string::npos || name.find('=') != std::string::npos) {
|
#ifdef DEBUG_BUILD
|
||||||
throw std::invalid_argument("name mustn't be empty or contain white spaces or equation chars");
|
if(name && *name) {
|
||||||
|
for(const char *c = name; *c; ++c) {
|
||||||
|
switch(*c) {
|
||||||
|
case ' ': case '=':
|
||||||
|
throw std::invalid_argument("name mustn't contain white spaces or equation chars");
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +151,7 @@ inline void Argument::setName(const std::string &name)
|
||||||
* The parser compares the abbreviation with the characters following a "-" prefix to
|
* The parser compares the abbreviation with the characters following a "-" prefix to
|
||||||
* identify arguments.
|
* identify arguments.
|
||||||
*/
|
*/
|
||||||
inline const std::string &Argument::abbreviation() const
|
inline const char *Argument::abbreviation() const
|
||||||
{
|
{
|
||||||
return m_abbreviation;
|
return m_abbreviation;
|
||||||
}
|
}
|
||||||
|
@ -157,11 +165,20 @@ inline const std::string &Argument::abbreviation() const
|
||||||
* The parser compares the abbreviation with the characters following a "-" prefix to
|
* The parser compares the abbreviation with the characters following a "-" prefix to
|
||||||
* identify arguments.
|
* identify arguments.
|
||||||
*/
|
*/
|
||||||
inline void Argument::setAbbreviation(const std::string &abbreviation)
|
inline void Argument::setAbbreviation(const char *abbreviation)
|
||||||
{
|
{
|
||||||
if(!abbreviation.empty() && (abbreviation.find(' ') != std::string::npos || abbreviation.find('=') != std::string::npos)) {
|
#ifdef DEBUG_BUILD
|
||||||
throw std::invalid_argument("abbreviation mustn't contain white spaces or equation chars");
|
if(abbreviation && *abbreviation) {
|
||||||
|
for(const char *c = abbreviation; *c; ++c) {
|
||||||
|
switch(*c) {
|
||||||
|
case ' ': case '=':
|
||||||
|
throw std::invalid_argument("abbreviation mustn't contain white spaces or equation chars");
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
m_abbreviation = abbreviation;
|
m_abbreviation = abbreviation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +187,7 @@ inline void Argument::setAbbreviation(const std::string &abbreviation)
|
||||||
*
|
*
|
||||||
* The parser uses the description when printing help information.
|
* The parser uses the description when printing help information.
|
||||||
*/
|
*/
|
||||||
inline const std::string &Argument::description() const
|
inline const char *Argument::description() const
|
||||||
{
|
{
|
||||||
return m_description;
|
return m_description;
|
||||||
}
|
}
|
||||||
|
@ -180,7 +197,7 @@ inline const std::string &Argument::description() const
|
||||||
*
|
*
|
||||||
* The parser uses the description when printing help information.
|
* The parser uses the description when printing help information.
|
||||||
*/
|
*/
|
||||||
inline void Argument::setDescription(const std::string &description)
|
inline void Argument::setDescription(const char *description)
|
||||||
{
|
{
|
||||||
m_description = description;
|
m_description = description;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +207,7 @@ inline void Argument::setDescription(const std::string &description)
|
||||||
*
|
*
|
||||||
* The parser uses the description when printing help information.
|
* The parser uses the description when printing help information.
|
||||||
*/
|
*/
|
||||||
inline const std::string &Argument::example() const
|
inline const char *Argument::example() const
|
||||||
{
|
{
|
||||||
return m_example;
|
return m_example;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +217,7 @@ inline const std::string &Argument::example() const
|
||||||
*
|
*
|
||||||
* The parser uses the description when printing help information.
|
* The parser uses the description when printing help information.
|
||||||
*/
|
*/
|
||||||
inline void Argument::setExample(const std::string &example)
|
inline void Argument::setExample(const char *example)
|
||||||
{
|
{
|
||||||
m_example = example;
|
m_example = example;
|
||||||
}
|
}
|
||||||
|
@ -564,7 +581,9 @@ public:
|
||||||
void printHelp(std::ostream &os) const;
|
void printHelp(std::ostream &os) const;
|
||||||
Argument *findArg(const ArgumentPredicate &predicate) const;
|
Argument *findArg(const ArgumentPredicate &predicate) const;
|
||||||
static Argument *findArg(const ArgumentVector &arguments, const ArgumentPredicate &predicate);
|
static Argument *findArg(const ArgumentVector &arguments, const ArgumentPredicate &predicate);
|
||||||
|
#ifdef DEBUG_BUILD
|
||||||
void verifySetup() const;
|
void verifySetup() const;
|
||||||
|
#endif
|
||||||
void parseArgs(int argc, char *argv[]);
|
void parseArgs(int argc, char *argv[]);
|
||||||
unsigned int actualArgumentCount() const;
|
unsigned int actualArgumentCount() const;
|
||||||
const std::string ¤tDirectory() const;
|
const std::string ¤tDirectory() const;
|
||||||
|
|
Loading…
Reference in New Issue