cpp-utilities/application/argumentparser.h

1217 lines
40 KiB
C
Raw Permalink Normal View History

#ifndef APPLICATION_UTILITIES_ARGUMENTPARSER_H
#define APPLICATION_UTILITIES_ARGUMENTPARSER_H
2015-04-22 18:36:40 +02:00
#include "../conversion/stringconversion.h"
#include "../misc/traits.h"
2015-04-22 18:36:40 +02:00
#include <functional>
2017-05-01 03:13:11 +02:00
#include <initializer_list>
2017-05-19 00:12:07 +02:00
#include <limits>
#include <tuple>
2023-02-03 13:31:18 +01:00
#include <vector>
2019-06-12 20:34:25 +02:00
#ifdef CPP_UTILITIES_DEBUG_BUILD
2017-05-01 03:13:11 +02:00
#include <cassert>
2016-06-12 01:56:57 +02:00
#endif
2015-04-22 18:36:40 +02:00
class ArgumentParserTests; // not a public class (only used for internal tests)
2016-07-03 22:36:48 +02:00
namespace CppUtilities {
2015-04-22 18:36:40 +02:00
/*!
* \brief Stores information about an application.
*/
struct ApplicationInfo {
const char *name = nullptr;
const char *author = nullptr;
const char *version = nullptr;
const char *url = nullptr;
2019-07-20 20:56:39 +02:00
const char *domain = nullptr;
2019-05-05 18:35:40 +02:00
const char *description = nullptr;
const char *license = nullptr;
const char *credits = nullptr;
std::vector<const char *> dependencyVersions;
};
/*!
* \brief Stores global application info used by ArgumentParser::printHelp() and AboutDialog.
*/
CPP_UTILITIES_EXPORT extern ApplicationInfo applicationInfo;
/*!
2017-11-06 19:47:17 +01:00
* \def SET_DEPENDENCY_INFO
* \brief Sets meta data about the dependencies the application was linked against which is
* used by ArgumentParser::printHelp().
* \remarks Reads those data from the config header so "config.h" must be included.
*/
#define SET_DEPENDENCY_INFO ::CppUtilities::applicationInfo.dependencyVersions = DEPENCENCY_VERSIONS
2015-08-25 19:12:05 +02:00
2016-10-30 00:30:54 +02:00
/*!
2017-11-06 19:47:17 +01:00
* \def SET_APPLICATION_INFO
* \brief Sets application meta data (including SET_DEPENDENCY_INFO) used by ArgumentParser::printHelp().
2016-10-30 00:30:54 +02:00
* \remarks Reads those data from the config header so "config.h" must be included.
*/
2017-05-01 03:13:11 +02:00
#define SET_APPLICATION_INFO \
::CppUtilities::applicationInfo.name = APP_NAME; \
::CppUtilities::applicationInfo.author = APP_AUTHOR; \
::CppUtilities::applicationInfo.version = APP_VERSION; \
::CppUtilities::applicationInfo.url = APP_URL; \
2019-07-20 20:56:39 +02:00
::CppUtilities::applicationInfo.domain = APP_DOMAIN; \
::CppUtilities::applicationInfo.description = APP_DESCRIPTION; \
::CppUtilities::applicationInfo.license = PROJECT_LICENSE; \
::CppUtilities::applicationInfo.credits = APP_CREDITS; \
2017-05-01 03:13:11 +02:00
SET_DEPENDENCY_INFO
2015-04-22 18:36:40 +02:00
2015-08-25 19:12:05 +02:00
class Argument;
2015-04-22 18:36:40 +02:00
class ArgumentParser;
class ArgumentReader;
2015-04-22 18:36:40 +02:00
using ArgumentInitializerList = std::initializer_list<Argument *>;
using ArgumentVector = std::vector<Argument *>;
using ArgumentPredicate = std::function<bool(Argument *)>;
2015-04-22 18:36:40 +02:00
2016-07-03 22:36:48 +02:00
/*!
* \brief The UnknownArgumentBehavior enum specifies the behavior of the argument parser when an unknown
* argument is detected.
*/
2017-05-01 03:13:11 +02:00
enum class UnknownArgumentBehavior {
2016-07-03 22:36:48 +02:00
Ignore, /**< Unknown arguments are ignored without warnings. */
Warn, /**< A warning is printed to std::cerr if an unknown argument is detected. */
Fail /**< Further parsing is aborted and a Failure instance with an error message is thrown. */
2016-07-03 22:36:48 +02:00
};
/*!
* \brief The ParseArgumentBehavior enum specifies the behavior when parsing arguments.
*
* This concerns checking constraints, invoking callbacks and handling failures. The values are supposed to be combined
* using the |-operator. Note that ParseArgumentBehavior::ReadArguments is always implied.
*/
enum class ParseArgumentBehavior {
ReadArguments = 0x0, /**< reads the specified CLI arguments, equivalent to simply calling readArgs() */
CheckConstraints = 0x1, /**< whether the constraints should be checked after reading the arguments */
InvokeCallbacks = 0x2, /**< whether the callbacks should be invoked after reading the arguments and (maybe) checking the constraints */
ExitOnFailure
= 0x4, /**< whether the parser should print an error message and terminate the application on failure (rather than throwing an exception) */
};
/// \cond
constexpr ParseArgumentBehavior operator|(ParseArgumentBehavior lhs, ParseArgumentBehavior rhs)
{
return static_cast<ParseArgumentBehavior>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
}
constexpr bool operator&(ParseArgumentBehavior lhs, ParseArgumentBehavior rhs)
{
return static_cast<bool>(static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs));
}
/// \endcond
2016-07-03 22:36:48 +02:00
/*!
* \brief The ValueCompletionBehavior enum specifies the items to be considered when generating completion for an argument value.
2017-09-30 18:42:34 +02:00
* \remarks
* - The enumeration items are meant to be combined using the |-operator.
* - ValueCompletionBehavior::InvokeCallback is meant to initialize pre-defined values only when required in the callback assigned
* via Argument::setCallback(). Hence it makes sense to combine it with ValueCompletionBehavior::PreDefinedValues.
* - When ValueCompletionBehavior::InvokeCallback is present, the callback assigned via Argument::setCallback() might be called
* even when not all constraints are fulfilled. So, for instance, there might not be all required values present.
2016-07-03 22:36:48 +02:00
*/
2017-05-01 03:13:11 +02:00
enum class ValueCompletionBehavior : unsigned char {
None = 0, /**< no auto-completion */
PreDefinedValues = 2, /**< values assigned with Argument::setPreDefinedCompletionValues() */
Files = 4, /**< files */
Directories = 8, /**< directories */
FileSystemIfNoPreDefinedValues = 16, /**< files and directories but only if no values have been assigned (default behavior) */
AppendEquationSign = 32, /**< an equation sign is appended to values which not contain an equation sign already */
InvokeCallback = 64, /**< whether to invoke the callback before reading pre-defined values */
2016-07-03 22:36:48 +02:00
};
/// \cond
2016-07-03 22:36:48 +02:00
constexpr ValueCompletionBehavior operator|(ValueCompletionBehavior lhs, ValueCompletionBehavior rhs)
{
return static_cast<ValueCompletionBehavior>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
}
constexpr bool operator&(ValueCompletionBehavior lhs, ValueCompletionBehavior rhs)
{
return static_cast<bool>(static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs));
}
/// \endcond
2016-07-03 22:36:48 +02:00
/*!
* \brief Contains functions to convert raw argument values to certain types.
*
* Extend this namespace by additional convert() functions to allow use of Argument::valuesAs() with your custom types.
*
* \remarks Still experimental. Might be removed/adjusted in next minor release.
*/
namespace ValueConversion {
template <typename TargetType, Traits::EnableIf<std::is_same<TargetType, std::string>> * = nullptr> TargetType convert(const char *value)
{
return std::string(value);
}
template <typename TargetType, Traits::EnableIf<std::is_arithmetic<TargetType>> * = nullptr> TargetType convert(const char *value)
{
return stringToNumber<TargetType>(value);
}
/// \cond
namespace Helper {
2018-09-29 20:52:13 +02:00
struct CPP_UTILITIES_EXPORT ArgumentValueConversionError {
const std::string errorMessage;
const char *const valueToConvert;
const char *const targetTypeName;
[[noreturn]] void throwFailure(const std::vector<Argument *> &argumentPath) const;
};
template <std::size_t N, typename FirstTargetType, typename... RemainingTargetTypes> struct ArgumentValueConverter {
static std::tuple<FirstTargetType, RemainingTargetTypes...> convertValues(std::vector<const char *>::const_iterator firstValue)
{
return std::tuple_cat(ArgumentValueConverter<1, FirstTargetType>::convertValues(firstValue),
ArgumentValueConverter<N - 1, RemainingTargetTypes...>::convertValues(firstValue + 1));
}
};
template <typename FirstTargetType, typename... RemainingTargetTypes> struct ArgumentValueConverter<1, FirstTargetType, RemainingTargetTypes...> {
static std::tuple<FirstTargetType> convertValues(std::vector<const char *>::const_iterator firstValue)
{
// FIXME: maybe use std::expected here when available
try {
return std::make_tuple<FirstTargetType>(ValueConversion::convert<FirstTargetType>(*firstValue));
} catch (const ConversionException &exception) {
throw ArgumentValueConversionError{ exception.what(), *firstValue, typeid(FirstTargetType).name() };
}
}
};
} // namespace Helper
/// \endcond
} // namespace ValueConversion
/*!
* \brief The ArgumentOccurrence struct holds argument values for an occurrence of an argument.
*/
2017-05-01 03:13:11 +02:00
struct CPP_UTILITIES_EXPORT ArgumentOccurrence {
ArgumentOccurrence(std::size_t index);
ArgumentOccurrence(std::size_t index, const std::vector<Argument *> parentPath, Argument *parent);
2016-07-03 22:36:48 +02:00
/*!
* \brief The index of the occurrence. This is not necessarily the index in the argv array.
*/
2016-07-03 22:36:48 +02:00
std::size_t index;
/*!
* \brief The parameter values which have been specified after the occurrence of the argument.
*/
2016-07-03 22:36:48 +02:00
std::vector<const char *> values;
/*!
* \brief The "path" of the occurrence (the parent elements which have been specified before).
* \remarks Empty for top-level occurrences.
*/
2016-07-03 22:36:48 +02:00
std::vector<Argument *> path;
template <typename... RemainingTargetTypes> std::tuple<RemainingTargetTypes...> convertValues() const;
private:
[[noreturn]] void throwNumberOfValuesNotSufficient(unsigned long valuesToConvert) const;
2016-07-03 22:36:48 +02:00
};
/*!
* \brief Converts the present values to the specified target types. There must be as many values present as types are specified.
* \throws Throws ArgumentUtilities::Failure when the number of present values is not sufficient or a conversion error occurs.
* \remarks Still experimental. Might be removed/adjusted in next minor release.
*/
template <typename... RemainingTargetTypes> std::tuple<RemainingTargetTypes...> ArgumentOccurrence::convertValues() const
{
constexpr auto valuesToConvert = sizeof...(RemainingTargetTypes);
if (values.size() < valuesToConvert) {
throwNumberOfValuesNotSufficient(valuesToConvert);
}
try {
return ValueConversion::Helper::ArgumentValueConverter<valuesToConvert, RemainingTargetTypes...>::convertValues(values.cbegin());
} catch (const ValueConversion::Helper::ArgumentValueConversionError &error) {
error.throwFailure(path);
}
}
/*!
* \brief Constructs an argument occurrence for the specified \a index.
*/
2017-05-01 03:13:11 +02:00
inline ArgumentOccurrence::ArgumentOccurrence(std::size_t index)
: index(index)
{
}
2016-07-03 22:36:48 +02:00
/*!
* \brief Constructs an argument occurrence.
* \param index Specifies the index.
* \param parentPath Specifies the path of \a parent.
* \param parent Specifies the parent which might be nullptr for top-level occurrences.
*
* The path of the new occurrence is built from the specified \a parentPath and \a parent.
*/
2017-05-01 03:13:11 +02:00
inline ArgumentOccurrence::ArgumentOccurrence(std::size_t index, const std::vector<Argument *> parentPath, Argument *parent)
: index(index)
, path(parentPath)
2016-07-03 22:36:48 +02:00
{
2017-05-01 03:13:11 +02:00
if (parent) {
2016-07-03 22:36:48 +02:00
path.push_back(parent);
}
}
2017-05-01 03:13:11 +02:00
class CPP_UTILITIES_EXPORT Argument {
friend ArgumentParser;
friend ArgumentReader;
2017-06-25 15:12:38 +02:00
friend ArgumentParserTests;
2015-04-22 18:36:40 +02:00
public:
2017-05-01 03:13:11 +02:00
typedef std::function<void(const ArgumentOccurrence &)> CallbackFunction;
2015-04-22 18:36:40 +02:00
/// \brief The Flags enum specifies options for treating the argument in a special way.
enum class Flags : std::uint64_t {
None = 0x0, /**< No flags are present. The default for Argument(). */
Combinable
= 0x1, /**< It is no error if this argument occurs besides other arguments on the same level. The default for ConfigValueArgument. */
Implicit = 0x2, /**< The argument is assumed to be present if its values are present. Only one argument can be implicit at the same level. */
Operation = 0x4, /**< The argument is an operation, so no `--` prefix is required when specifying it. The default for OperationArgument(). */
Deprecated = 0x8, /**< The argument is considered deprecated and therefore excluded from the help. */
Greedy
= 0x10, /**< The argument is "greedy" so when Argument::varValueCount is used all subsequent arguments will be considered values of that argument. This is useful to pass remaining arguments down to another argument parser as-is. */
};
2016-06-12 01:56:57 +02:00
Argument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);
2015-04-22 18:36:40 +02:00
~Argument();
// declare getter/setter/properties/operations for argument definition:
// - those properties must be set *before* parsing
// - they control the behaviour of the parser, eg.
// - the name/abbreviation to look for
// - constraints to be checked
// - callbacks to be invoked
// TODO v5: It would make sense to move these to a separate class (eg. ArgumentDefinition) to prevent this one from
// becoming to big.
const char *name() const;
void setName(const char *name);
2016-06-12 01:56:57 +02:00
char abbreviation() const;
void setAbbreviation(char abbreviation);
const char *environmentVariable() const;
void setEnvironmentVariable(const char *environmentVariable);
const char *description() const;
void setDescription(const char *description);
const char *example() const;
void setExample(const char *example);
2016-06-12 01:56:57 +02:00
std::size_t requiredValueCount() const;
void setRequiredValueCount(std::size_t requiredValueCount);
const std::vector<const char *> &valueNames() const;
void setValueNames(std::initializer_list<const char *> valueNames);
2015-04-22 18:36:40 +02:00
void appendValueName(const char *valueName);
2016-06-12 01:56:57 +02:00
void setConstraints(std::size_t minOccurrences, std::size_t maxOccurrences);
const std::vector<Argument *> &path(std::size_t occurrence = 0) const;
2015-04-22 18:36:40 +02:00
bool isRequired() const;
2016-06-12 01:56:57 +02:00
void setRequired(bool required);
Argument::Flags flags() const;
void setFlags(Argument::Flags flags);
void setFlags(Argument::Flags flags, bool add);
2015-04-22 18:36:40 +02:00
bool isCombinable() const;
void setCombinable(bool combinable);
2015-04-22 18:36:40 +02:00
bool isImplicit() const;
void setImplicit(bool implicit);
2015-05-08 23:20:47 +02:00
bool denotesOperation() const;
void setDenotesOperation(bool denotesOperation);
const CallbackFunction &callback() const;
2015-04-22 18:36:40 +02:00
void setCallback(CallbackFunction callback);
const ArgumentVector &subArguments() const;
void setSubArguments(const ArgumentInitializerList &subArguments);
void addSubArguments(const ArgumentInitializerList &subArguments);
void addSubArgument(Argument *arg);
bool hasSubArguments() const;
2019-06-04 19:08:46 +02:00
const ArgumentVector &parents() const;
void printInfo(std::ostream &os, unsigned char indentation = 0) const;
// declare getter/setter/properties for bash completion: those properties must be set *before parsing
2016-07-03 22:36:48 +02:00
ValueCompletionBehavior valueCompletionBehaviour() const;
void setValueCompletionBehavior(ValueCompletionBehavior valueCompletionBehaviour);
const char *preDefinedCompletionValues() const;
void setPreDefinedCompletionValues(const char *preDefinedCompletionValues);
// declare getter/read-only properties for parsing results: those properties will be populated when parsing
const std::vector<const char *> &values(std::size_t occurrence = 0) const;
template <typename... TargetType> std::tuple<TargetType...> valuesAs(std::size_t occurrence = 0) const;
template <typename... TargetType> std::vector<std::tuple<TargetType...>> allValuesAs() const;
const char *firstValue() const;
const char *firstValueOr(const char *fallback) const;
bool allRequiredValuesPresent(std::size_t occurrence = 0) const;
bool isPresent() const;
std::size_t occurrences() const;
std::size_t index(std::size_t occurrence) const;
std::size_t minOccurrences() const;
std::size_t maxOccurrences() const;
2019-05-04 23:14:43 +02:00
bool isDeprecated() const;
const Argument *deprecatedBy() const;
void markAsDeprecated(const Argument *deprecatedBy = nullptr);
bool isMainArgument() const;
bool isParentPresent() const;
2015-04-22 18:36:40 +02:00
Argument *conflictsWithArgument() const;
Argument *wouldConflictWithArgument() const;
2017-09-26 16:46:17 +02:00
Argument *specifiedOperation() const;
const std::vector<ArgumentOccurrence> &occurrenceInfo() const;
std::vector<ArgumentOccurrence> &occurrenceInfo();
void reset();
void resetRecursively();
2015-04-22 18:36:40 +02:00
2017-05-19 00:12:07 +02:00
/*!
* \brief Denotes a variable number of values.
* \sa setRequiredValueCount()
*/
static constexpr std::size_t varValueCount = std::numeric_limits<std::size_t>::max();
2015-04-22 18:36:40 +02:00
private:
// declare internal getter/setter/properties/operations for argument definition
2020-11-25 17:51:13 +01:00
bool matchesDenotation(const char *denotation, std::size_t denotationLength) const;
2017-11-29 21:52:16 +01:00
const char *m_name;
2016-06-12 01:56:57 +02:00
char m_abbreviation;
const char *m_environmentVar;
const char *m_description;
const char *m_example;
2016-06-12 01:56:57 +02:00
std::size_t m_minOccurrences;
std::size_t m_maxOccurrences;
std::size_t m_requiredValueCount;
std::vector<const char *> m_valueNames;
Flags m_flags;
std::vector<ArgumentOccurrence> m_occurrences;
ArgumentVector m_subArgs;
2015-04-22 18:36:40 +02:00
CallbackFunction m_callbackFunction;
ArgumentVector m_parents;
2019-05-04 23:14:43 +02:00
const Argument *m_deprecatedBy;
2015-04-22 18:36:40 +02:00
bool m_isMainArg;
2016-07-03 22:36:48 +02:00
ValueCompletionBehavior m_valueCompletionBehavior;
const char *m_preDefinedCompletionValues;
};
/// \cond
constexpr Argument::Flags operator|(Argument::Flags lhs, Argument::Flags rhs)
{
return static_cast<Argument::Flags>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
}
constexpr bool operator&(Argument::Flags lhs, Argument::Flags rhs)
{
return static_cast<bool>(static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs));
}
/// \endcond
/*!
* \brief Converts the present values for the specified \a occurrence to the specified target types. There must be as many values present as types are specified.
* \throws Throws ArgumentUtilities::Failure when the number of present values is not sufficient or a conversion error occurs.
* \remarks Still experimental. Might be removed/adjusted in next minor release.
*/
template <typename... TargetType> std::tuple<TargetType...> Argument::valuesAs(std::size_t occurrence) const
{
return m_occurrences[occurrence].convertValues<TargetType...>();
}
/*!
* \brief Converts the present values for all occurrence to the specified target types. For each occurrence, there must be as many values present as types are specified.
* \throws Throws ArgumentUtilities::Failure when the number of present values is not sufficient or a conversion error occurs.
* \remarks Still experimental. Might be removed/adjusted in next minor release.
*/
template <typename... TargetType> std::vector<std::tuple<TargetType...>> Argument::allValuesAs() const
{
std::vector<std::tuple<TargetType...>> res;
res.reserve(m_occurrences.size());
for (const auto &occurrence : m_occurrences) {
res.emplace_back(occurrence.convertValues<TargetType...>());
}
return res;
}
class CPP_UTILITIES_EXPORT HelpArgument : public Argument {
public:
HelpArgument(ArgumentParser &parser);
};
class CPP_UTILITIES_EXPORT OperationArgument : public Argument {
public:
OperationArgument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);
};
class CPP_UTILITIES_EXPORT ConfigValueArgument : public Argument {
public:
ConfigValueArgument(const char *name, char abbreviation = '\0', const char *description = nullptr,
std::initializer_list<const char *> valueNames = std::initializer_list<const char *>());
};
class CPP_UTILITIES_EXPORT NoColorArgument : public Argument {
friend ArgumentParserTests;
public:
NoColorArgument();
void apply() const;
};
struct ArgumentCompletionInfo;
2017-05-01 03:13:11 +02:00
class CPP_UTILITIES_EXPORT ArgumentParser {
2016-07-03 22:36:48 +02:00
friend ArgumentParserTests;
friend ArgumentReader;
2016-07-03 22:36:48 +02:00
public:
ArgumentParser();
// declare getter/setter for argument definitions
2016-07-03 22:36:48 +02:00
const ArgumentVector &mainArguments() const;
void setMainArguments(const ArgumentInitializerList &mainArguments);
void addMainArgument(Argument *argument);
// declare operations which will consider previously assigned argument definitions and maybe modify parsing results
2016-07-03 22:36:48 +02:00
void printHelp(std::ostream &os) const;
void parseArgs(int argc, const char *const *argv,
ParseArgumentBehavior behavior
= ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks | ParseArgumentBehavior::ExitOnFailure);
void readArgs(int argc, const char *const *argv);
void resetArgs();
void checkConstraints();
void invokeCallbacks();
// declare getter for parsing results
2016-07-03 22:36:48 +02:00
unsigned int actualArgumentCount() const;
const char *executable() const;
UnknownArgumentBehavior unknownArgumentBehavior() const;
void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior);
Argument *defaultArgument() const;
void setDefaultArgument(Argument *argument);
2017-09-26 16:46:17 +02:00
Argument *specifiedOperation() const;
bool isUncombinableMainArgPresent() const;
void setExitFunction(std::function<void(int)> exitFunction);
const HelpArgument &helpArg() const;
HelpArgument &helpArg();
const NoColorArgument &noColorArg() const;
NoColorArgument &noColorArg();
2016-07-03 22:36:48 +02:00
private:
// declare internal operations
2019-06-12 20:34:25 +02:00
CPP_UTILITIES_IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args);)
ArgumentCompletionInfo determineCompletionInfo(
int argc, const char *const *argv, unsigned int currentWordIndex, const ArgumentReader &reader) const;
std::string findSuggestions(int argc, const char *const *argv, unsigned int cursorPos, const ArgumentReader &reader) const;
void printBashCompletion(int argc, const char *const *argv, unsigned int cursorPos, const ArgumentReader &reader) const;
2016-07-03 22:36:48 +02:00
void checkConstraints(const ArgumentVector &args);
static void invokeCallbacks(const ArgumentVector &args);
void invokeExit(int code);
2016-07-03 22:36:48 +02:00
ArgumentVector m_mainArgs;
unsigned int m_actualArgc;
const char *m_executable;
UnknownArgumentBehavior m_unknownArgBehavior;
Argument *m_defaultArg;
HelpArgument m_helpArg;
NoColorArgument m_noColorArg;
std::function<void(int)> m_exitFunction;
2015-04-22 18:36:40 +02:00
};
/*!
* \brief Returns the name of the argument.
*
* The parser compares the name with the characters following a "--" prefix to identify arguments.
2015-04-22 18:36:40 +02:00
*/
inline const char *Argument::name() const
2015-04-22 18:36:40 +02:00
{
return m_name;
}
/*!
* \brief Sets the name of the argument.
*
* The name mustn't be empty, start with a minus or contain white spaces, equation chars, quotes and newlines.
2015-04-22 18:36:40 +02:00
*
* The parser compares the name with the characters following a "--" prefix to identify arguments.
2015-04-22 18:36:40 +02:00
*/
inline void Argument::setName(const char *name)
{
#if defined(CPP_UTILITIES_DEBUG_BUILD) && !defined(_MSC_VER)
2017-05-01 03:13:11 +02:00
if (name && *name) {
assert(*name != '-');
2017-05-01 03:13:11 +02:00
for (const char *c = name; *c; ++c) {
assert(*c != ' ' && *c != '=' && *c != '\'' && *c != '\"' && *c != '\n' && *c != '\r');
}
2015-04-22 18:36:40 +02:00
}
#endif
2015-04-22 18:36:40 +02:00
m_name = name;
}
/*!
* \brief Returns the abbreviation of the argument.
*
* The parser compares the abbreviation with the characters following a "-" prefix to identify arguments.
2015-04-22 18:36:40 +02:00
*/
2016-06-12 01:56:57 +02:00
inline char Argument::abbreviation() const
2015-04-22 18:36:40 +02:00
{
return m_abbreviation;
}
/*!
* \brief Sets the abbreviation of the argument.
*
* The abbreviation might be empty but mustn't be white spaces, equation char, single quote, double quote or newline.
2015-04-22 18:36:40 +02:00
*
* The parser compares the abbreviation with the characters following a "-" prefix to identify arguments.
2015-04-22 18:36:40 +02:00
*/
2016-06-12 01:56:57 +02:00
inline void Argument::setAbbreviation(char abbreviation)
{
2019-06-12 20:34:25 +02:00
CPP_UTILITIES_IF_DEBUG_BUILD(assert(abbreviation != ' ' && abbreviation != '=' && abbreviation != '-' && abbreviation != '\''
&& abbreviation != '"' && abbreviation != '\n' && abbreviation != '\r'));
2015-04-22 18:36:40 +02:00
m_abbreviation = abbreviation;
}
/*!
* \brief Returns the environment variable queried when firstValue() is called.
* \sa firstValue(), setEnvironmentVariable()
*/
inline const char *Argument::environmentVariable() const
{
return m_environmentVar;
}
/*!
* \brief Sets the environment variable queried when firstValue() is called.
* \sa firstValue(), environmentVariable()
*/
inline void Argument::setEnvironmentVariable(const char *environmentVariable)
{
m_environmentVar = environmentVariable;
}
2015-04-22 18:36:40 +02:00
/*!
* \brief Returns the description of the argument.
*
* The parser uses the description when printing help information.
*/
inline const char *Argument::description() const
2015-04-22 18:36:40 +02:00
{
return m_description;
}
/*!
* \brief Sets the description of the argument.
*
* The parser uses the description when printing help information.
*/
inline void Argument::setDescription(const char *description)
2015-04-22 18:36:40 +02:00
{
m_description = description;
}
2015-10-06 22:27:16 +02:00
/*!
* \brief Returns the usage example of the argument.
*
* The parser uses the description when printing help information.
*/
inline const char *Argument::example() const
2015-10-06 22:27:16 +02:00
{
return m_example;
}
/*!
* \brief Sets the a usage example for the argument.
*
* The parser uses the description when printing help information.
*/
inline void Argument::setExample(const char *example)
2015-10-06 22:27:16 +02:00
{
m_example = example;
}
2015-04-22 18:36:40 +02:00
/*!
* \brief Returns the parameter values for the specified \a occurrence of argument.
* \remarks
* - The values are set by the parser when parsing the command line arguments.
* - The specified \a occurrence must be less than occurrences().
2015-04-22 18:36:40 +02:00
*/
inline const std::vector<const char *> &Argument::values(std::size_t occurrence) const
2015-04-22 18:36:40 +02:00
{
return m_occurrences[occurrence].values;
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns the number of values which are required to be given
* for this argument.
*
* The parser will expect that many values when parsing command line arguments.
* A negative value indicates a variable number of arguments to be expected.
*
2016-10-30 00:30:54 +02:00
* The default value is 0, except for ConfigValueArgument instances.
2015-04-22 18:36:40 +02:00
*
* \sa setRequiredValueCount()
* \sa valueNames()
* \sa setValueNames()
*/
2016-06-12 01:56:57 +02:00
inline std::size_t Argument::requiredValueCount() const
2015-04-22 18:36:40 +02:00
{
return m_requiredValueCount;
}
/*!
* \brief Sets the number of values which are required to be given
* for this argument.
*
* The parser will expect that many values when parsing command line arguments.
2017-05-19 00:12:07 +02:00
* Pass Argument::varValueCount for a variable number of arguments
* to be expected.
2015-04-22 18:36:40 +02:00
*
* \sa requiredValueCount()
* \sa valueNames()
* \sa setValueNames()
*/
2016-06-12 01:56:57 +02:00
inline void Argument::setRequiredValueCount(std::size_t requiredValueCount)
2015-04-22 18:36:40 +02:00
{
m_requiredValueCount = requiredValueCount;
}
/*!
* \brief Returns the names of the required values.
2015-04-22 18:36:40 +02:00
*
* These names will be shown when printing information about the argument.
*
* \sa setValueNames()
2016-09-17 11:44:49 +02:00
* \sa appendValueName()
2015-04-22 18:36:40 +02:00
*/
2016-06-12 01:56:57 +02:00
inline const std::vector<const char *> &Argument::valueNames() const
2015-04-22 18:36:40 +02:00
{
return m_valueNames;
}
/*!
* \brief Sets the names of the required values. These names will be used
2015-04-22 18:36:40 +02:00
* when printing information about the argument.
*
* If the number of value names is higher than the number of required values
2015-04-22 18:36:40 +02:00
* the additional value names will be ignored.
* If the number of value names is lesser than the number of required values
2015-04-22 18:36:40 +02:00
* generic values will be used for the missing names.
*
* \sa appendValueName()
* \sa valueNames()
* \sa requiredValueCount()
*/
inline void Argument::setValueNames(std::initializer_list<const char *> valueNames)
2015-04-22 18:36:40 +02:00
{
m_valueNames.assign(valueNames);
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Appends a value name. The value names names will be shown
* when printing information about the argument.
* \sa setValueNames()
* \sa valueNames()
*/
inline void Argument::appendValueName(const char *valueName)
2015-04-22 18:36:40 +02:00
{
m_valueNames.emplace_back(valueName);
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns an indication whether all required values are present.
*/
inline bool Argument::allRequiredValuesPresent(std::size_t occurrence) const
2015-04-22 18:36:40 +02:00
{
2017-11-06 19:49:39 +01:00
return m_requiredValueCount == Argument::varValueCount
2017-05-01 03:13:11 +02:00
|| (m_occurrences[occurrence].values.size() >= static_cast<std::size_t>(m_requiredValueCount));
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns an indication whether the argument is an implicit argument.
* \sa setImplicit()
2015-04-22 18:36:40 +02:00
*/
inline bool Argument::isImplicit() const
2015-04-22 18:36:40 +02:00
{
return m_flags & Flags::Implicit;
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Sets whether the argument is an implicit argument.
* \sa isImplicit()
2015-04-22 18:36:40 +02:00
*/
inline void Argument::setImplicit(bool implicit)
2015-04-22 18:36:40 +02:00
{
setFlags(Flags::Implicit, implicit);
2015-04-22 18:36:40 +02:00
}
/*!
2016-06-12 01:56:57 +02:00
* \brief Returns an indication whether the argument could be detected when parsing.
2015-04-22 18:36:40 +02:00
*/
inline bool Argument::isPresent() const
{
return !m_occurrences.empty();
2016-06-12 01:56:57 +02:00
}
/*!
* \brief Returns how often the argument could be detected when parsing.
*/
inline std::size_t Argument::occurrences() const
{
return m_occurrences.size();
2016-06-12 01:56:57 +02:00
}
/*!
* \brief Returns the indices of the argument's occurrences which could be detected when parsing.
2016-06-12 01:56:57 +02:00
*/
inline std::size_t Argument::index(std::size_t occurrence) const
2016-06-12 01:56:57 +02:00
{
return m_occurrences[occurrence].index;
2016-06-12 01:56:57 +02:00
}
/*!
* \brief Returns the minimum number of occurrences.
*
* If the argument occurs not that many times, the parser will complain.
*/
inline std::size_t Argument::minOccurrences() const
{
return m_minOccurrences;
}
/*!
* \brief Returns the maximum number of occurrences.
*
* If the argument occurs more often, the parser will complain.
*/
inline std::size_t Argument::maxOccurrences() const
{
return m_maxOccurrences;
}
2019-05-04 23:14:43 +02:00
inline bool Argument::isDeprecated() const
{
return m_flags & Flags::Deprecated;
}
/*!
* \brief Returns the argument which obsoletes this argument.
*/
inline const Argument *Argument::deprecatedBy() const
{
return m_deprecatedBy;
}
/*!
* \brief Marks the argument as deprecated.
*
* If another argument should be used instead, specify it via \a deprecatedBy.
*/
inline void Argument::markAsDeprecated(const Argument *deprecatedBy)
{
setFlags(Flags::Deprecated, true);
m_deprecatedBy = deprecatedBy;
}
2016-06-12 01:56:57 +02:00
/*!
* \brief Sets the allowed number of occurrences.
* \sa minOccurrences()
* \sa maxOccurrences()
*/
inline void Argument::setConstraints(std::size_t minOccurrences, std::size_t maxOccurrences)
{
m_minOccurrences = minOccurrences;
m_maxOccurrences = maxOccurrences;
2015-04-22 18:36:40 +02:00
}
2016-07-03 22:36:48 +02:00
/*!
* \brief Returns the path of the specified \a occurrence.
2016-07-03 22:36:48 +02:00
*/
inline const std::vector<Argument *> &Argument::path(std::size_t occurrence) const
2016-07-03 22:36:48 +02:00
{
return m_occurrences[occurrence].path;
2016-07-03 22:36:48 +02:00
}
2015-04-22 18:36:40 +02:00
/*!
* \brief Returns an indication whether the argument is mandatory.
*
* The parser will complain if a mandatory argument is not present.
*
* The default value is false.
*
* \sa setRequired()
*/
inline bool Argument::isRequired() const
{
2016-06-12 01:56:57 +02:00
return m_minOccurrences;
2015-04-22 18:36:40 +02:00
}
/*!
2016-06-12 01:56:57 +02:00
* \brief Sets whether this argument is mandatory or not.
2015-04-22 18:36:40 +02:00
*
* The parser will complain if a mandatory argument is not present.
*
* * \sa isRequired()
*/
2016-06-12 01:56:57 +02:00
inline void Argument::setRequired(bool required)
2015-04-22 18:36:40 +02:00
{
2017-05-01 03:13:11 +02:00
if (required) {
if (!m_minOccurrences) {
2016-06-12 01:56:57 +02:00
m_minOccurrences = 1;
}
} else {
m_minOccurrences = 0;
}
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns Argument::Flags for the argument.
*/
inline Argument::Flags Argument::flags() const
{
return m_flags;
}
/*!
* \brief Replaces all Argument::Flags for the argument with the \a flags.
*/
inline void Argument::setFlags(Argument::Flags flags)
{
m_flags = flags;
}
/*!
* \brief Adds or removes the specified \a flags.
*/
inline void Argument::setFlags(Argument::Flags flags, bool add)
{
m_flags = add ? (m_flags | flags)
: static_cast<Argument::Flags>(static_cast<std::underlying_type<Argument::Flags>::type>(m_flags)
2024-04-08 12:33:57 +02:00
& ~static_cast<std::underlying_type<Argument::Flags>::type>(flags));
}
2015-04-22 18:36:40 +02:00
/*!
* \brief Returns an indication whether the argument is combinable.
*
* The parser will complain if two arguments labeled as uncombinable are
* present at the same time.
*
* \sa setCombinable()
*/
inline bool Argument::isCombinable() const
{
return m_flags & Flags::Combinable;
2015-04-22 18:36:40 +02:00
}
/*!
2016-10-30 00:30:54 +02:00
* \brief Sets whether this argument can be combined.
2015-04-22 18:36:40 +02:00
*
* The parser will complain if two arguments labeled as uncombinable are
* present at the same time.
*
* \sa isCombinable()
*/
inline void Argument::setCombinable(bool combinable)
2015-04-22 18:36:40 +02:00
{
setFlags(Flags::Combinable, combinable);
2015-04-22 18:36:40 +02:00
}
2015-05-08 23:20:47 +02:00
/*!
2018-05-11 16:15:02 +02:00
* \brief Returns whether the argument denotes an operation.
2015-05-08 23:20:47 +02:00
*
2018-05-11 16:15:02 +02:00
* An argument which denotes an operation might be specified
* without "--" or "-" prefix.
2015-05-08 23:20:47 +02:00
*
2016-10-30 00:30:54 +02:00
* The default value is false, except for OperationArgument instances.
2015-05-08 23:20:47 +02:00
*
* \sa setDenotesOperation()
*/
inline bool Argument::denotesOperation() const
{
return m_flags & Flags::Operation;
2015-05-08 23:20:47 +02:00
}
/*!
* \brief Sets whether the argument denotes the operation.
* \sa denotesOperation()
*/
inline void Argument::setDenotesOperation(bool denotesOperation)
{
setFlags(Flags::Operation, denotesOperation);
2015-05-08 23:20:47 +02:00
}
/*!
* \brief Returns the assigned callback function.
* \sa setCallback()
*/
inline const Argument::CallbackFunction &Argument::callback() const
{
return m_callbackFunction;
}
2015-04-22 18:36:40 +02:00
/*!
* \brief Sets a \a callback function which will be called by the parser if
* the argument could be found and no parsing errors occurred.
* \remarks The \a callback will be called for each occurrence of the argument.
* \sa callback()
2015-04-22 18:36:40 +02:00
*/
inline void Argument::setCallback(Argument::CallbackFunction callback)
{
m_callbackFunction = callback;
}
/*!
* \brief Returns the secondary arguments for this argument.
*
* \sa setSubArguments()
* \sa hasSubArguments()
2015-04-22 18:36:40 +02:00
*/
inline const ArgumentVector &Argument::subArguments() const
2015-04-22 18:36:40 +02:00
{
return m_subArgs;
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns an indication whether the argument has secondary arguments.
*
* \sa secondaryArguments()
* \sa setSubArguments()
2015-04-22 18:36:40 +02:00
*/
inline bool Argument::hasSubArguments() const
2015-04-22 18:36:40 +02:00
{
return !m_subArgs.empty();
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns the parents of this argument.
*
* If this argument is used as secondary argument, the arguments which
* contain this argument as secondary arguments are returned
* as "parents" of this argument.
*
* If this argument is used as a main argument shouldn't be used as
* secondary argument at the same time and thus have no parents.
*/
2019-06-04 19:08:46 +02:00
inline const ArgumentVector &Argument::parents() const
2015-04-22 18:36:40 +02:00
{
return m_parents;
}
/*!
* \brief Returns an indication whether the argument is used as main argument.
*
* An argument used as main argument shouldn't be used as secondary
* arguments at the same time.
*/
inline bool Argument::isMainArgument() const
{
return m_isMainArg;
}
2016-07-03 22:36:48 +02:00
/*!
* \brief Returns the items to be considered when generating completion for the values.
*
* By default, files and directories are considered, unless pre-defined values have been
* specified using setPreDefinedCompletionValues().
2016-07-03 22:36:48 +02:00
*/
inline ValueCompletionBehavior Argument::valueCompletionBehaviour() const
2015-04-22 18:36:40 +02:00
{
2016-07-03 22:36:48 +02:00
return m_valueCompletionBehavior;
}
2015-04-22 18:36:40 +02:00
2016-07-03 22:36:48 +02:00
/*!
* \brief Sets the items to be considered when generating completion for the values.
*
* By default, files and directories are considered, unless pre-defined values have been
* specified using setPreDefinedCompletionValues().
2016-07-03 22:36:48 +02:00
*/
inline void Argument::setValueCompletionBehavior(ValueCompletionBehavior completionValues)
{
m_valueCompletionBehavior = completionValues;
}
2015-04-22 18:36:40 +02:00
2016-07-03 22:36:48 +02:00
/*!
* \brief Returns the assigned values used when generating completion for the values.
*/
inline const char *Argument::preDefinedCompletionValues() const
{
return m_preDefinedCompletionValues;
}
2016-06-12 01:56:57 +02:00
2016-07-03 22:36:48 +02:00
/*!
* \brief Assigns the values to be used when generating completion for the values.
2016-07-03 22:36:48 +02:00
*/
inline void Argument::setPreDefinedCompletionValues(const char *preDefinedCompletionValues)
{
m_preDefinedCompletionValues = preDefinedCompletionValues;
}
/*!
* \brief Resets occurrences (indices, values and paths).
*
* So parsing results are wiped while the argument definition is preserved.
2016-07-03 22:36:48 +02:00
*/
inline void Argument::reset()
{
m_occurrences.clear();
2016-07-03 22:36:48 +02:00
}
2015-04-22 18:36:40 +02:00
inline OperationArgument::OperationArgument(const char *name, char abbreviation, const char *description, const char *example)
: Argument(name, abbreviation, description, example)
{
setDenotesOperation(true);
}
/*!
* \brief Constructs a new ConfigValueArgument with the specified parameter. The initial value of requiredValueCount() is set to size of specified \a valueNames.
*/
inline ConfigValueArgument::ConfigValueArgument(
const char *name, char abbreviation, const char *description, std::initializer_list<const char *> valueNames)
: Argument(name, abbreviation, description)
{
setCombinable(true);
setRequiredValueCount(valueNames.size());
setValueNames(valueNames);
}
/*!
* \brief Returns information about all occurrences of the argument which have been detected when parsing.
* \remarks The convenience methods isPresent(), values() and path() provide direct access to these information for a particular occurrence.
*/
inline const std::vector<ArgumentOccurrence> &Argument::occurrenceInfo() const
{
return m_occurrences;
}
/*!
* \brief Returns information about all occurrences of the argument which have been detected when parsing.
* \remarks
* This information is meant to be set by the ArgumentParser. Modifying it directly is likely not a good idea. This method has been
* added primarily for testing purposes. In this case it might make sense to skip the actual parsing and just provide some dummy values.
*/
inline std::vector<ArgumentOccurrence> &Argument::occurrenceInfo()
{
return m_occurrences;
}
2015-04-22 18:36:40 +02:00
/*!
* \brief Returns the main arguments.
* \sa setMainArguments()
*/
inline const ArgumentVector &ArgumentParser::mainArguments() const
{
return m_mainArgs;
}
/*!
* \brief Returns the actual number of arguments that could be found when parsing.
*/
inline unsigned int ArgumentParser::actualArgumentCount() const
{
return m_actualArgc;
}
/*!
* \brief Returns the name of the current executable.
2015-04-22 18:36:40 +02:00
*/
inline const char *ArgumentParser::executable() const
2015-04-22 18:36:40 +02:00
{
return m_executable;
2015-04-22 18:36:40 +02:00
}
/*!
2016-07-03 22:36:48 +02:00
* \brief Returns how unknown arguments are treated.
2015-04-22 18:36:40 +02:00
*
2016-07-03 22:36:48 +02:00
* The default value is UnknownArgumentBehavior::Fail.
2015-04-22 18:36:40 +02:00
*/
2016-07-03 22:36:48 +02:00
inline UnknownArgumentBehavior ArgumentParser::unknownArgumentBehavior() const
2015-04-22 18:36:40 +02:00
{
2016-07-03 22:36:48 +02:00
return m_unknownArgBehavior;
2015-04-22 18:36:40 +02:00
}
/*!
2016-07-03 22:36:48 +02:00
* \brief Sets how unknown arguments are treated.
2015-04-22 18:36:40 +02:00
*
2016-07-03 22:36:48 +02:00
* The default value is UnknownArgumentBehavior::Fail.
2015-04-22 18:36:40 +02:00
*/
2016-07-03 22:36:48 +02:00
inline void ArgumentParser::setUnknownArgumentBehavior(UnknownArgumentBehavior behavior)
2015-04-22 18:36:40 +02:00
{
2016-07-03 22:36:48 +02:00
m_unknownArgBehavior = behavior;
2015-04-22 18:36:40 +02:00
}
/*!
* \brief Returns the default argument.
* \remarks The default argument is assumed to be present if no other arguments have been specified.
*/
inline Argument *ArgumentParser::defaultArgument() const
{
return m_defaultArg;
}
/*!
* \brief Sets the default argument.
* \remarks The default argument is assumed to be present if no other arguments have been specified.
*/
inline void ArgumentParser::setDefaultArgument(Argument *argument)
{
m_defaultArg = argument;
}
/*!
* \brief Checks whether constraints are violated.
* \remarks Automatically called by parseArgs().
* \throws Throws Failure if constraints are violated.
*/
inline void ArgumentParser::checkConstraints()
{
checkConstraints(m_mainArgs);
}
/*!
* \brief Invokes all assigned callbacks.
* \remarks Automatically called by parseArgs().
*/
inline void ArgumentParser::invokeCallbacks()
{
invokeCallbacks(m_mainArgs);
}
/*!
* \brief Specifies a function quit the application.
* \remarks Currently only used after printing Bash completion. Default is std::exit().
*/
inline void ArgumentParser::setExitFunction(std::function<void(int)> exitFunction)
{
m_exitFunction = exitFunction;
}
2016-10-30 00:30:54 +02:00
/*!
* \brief Returns the `--help` argument.
2016-10-30 00:30:54 +02:00
*/
inline const HelpArgument &ArgumentParser::helpArg() const
{
return m_helpArg;
}
2017-10-17 00:00:46 +02:00
/*!
* \brief Returns the `--help` argument.
*/
inline HelpArgument &ArgumentParser::helpArg()
{
return m_helpArg;
}
2018-01-29 16:23:10 +01:00
/*!
* \brief Returns the `--no-color` argument.
*/
inline const NoColorArgument &ArgumentParser::noColorArg() const
{
return m_noColorArg;
}
2017-10-17 00:00:46 +02:00
/*!
* \brief Returns the `--no-color` argument.
*/
inline NoColorArgument &ArgumentParser::noColorArg()
{
return m_noColorArg;
}
2017-10-17 00:00:46 +02:00
} // namespace CppUtilities
2015-04-22 18:36:40 +02:00
#endif // APPLICATION_UTILITIES_ARGUMENTPARSER_H