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:
Martchus 2016-05-25 01:24:17 +02:00
parent 2a58a83c3c
commit f3077ef8e3
2 changed files with 83 additions and 80 deletions

View File

@ -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;

View File

@ -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 &currentDirectory() const; const std::string &currentDirectory() const;