X-Git-Url: https://git.dlugolecki.net.pl/?a=blobdiff_plain;f=include%2Foption.h;h=7e9917b589c7021a0c5852695e90eecb5fa36908;hb=f2d683504e2dc76868ec84d7c1fd858edc0df5a4;hp=a77d8f446d19f179b9799ae5f7393d23c4240042;hpb=c85d60a873e21052a470c172df4ba56a1c0d59c6;p=command.git diff --git a/include/option.h b/include/option.h index a77d8f4..7e9917b 100644 --- a/include/option.h +++ b/include/option.h @@ -6,35 +6,35 @@ #include #include "parameter.h" +#include "exception/missingOptionValue.h" +#include "exception/optionFailedConversion.h" +#include "exception/optionValueNotSpecified.h" namespace command { /** * Class responsible for handling commandline options. - * Options are non-required, named parameters of program. + * Options are named parameters of program. * * Example: - * ./myprog OptionName=OptionValue - * ./myprog -f=/some/file - * ./myprog --level=15 + * - ./myprog OptionName=OptionValue + * - ./myprog -f=/some/file + * - ./myprog --level=15 */ - template + template class Option - : public Parameter, public Callable { + : public Parameter, public Callable { public: typedef std::string OptionName; protected: /** * Current Option name */ - OptionName name; + const OptionName name; /** * Current Option value */ - OptionType value; - - /** Variable indicating if current Option was already used or not */ - bool used = false; + ParameterType value; public: /** @@ -44,8 +44,8 @@ namespace command { * @param description Description of current Option * @param function Function used to handle current Option. */ - Option(std::string name, const std::string & description, void (*function)(OptionType)) - : Parameter(description), Callable(function), name(name) { + Option(const std::string & name, const std::string & description, void (*function)(ParameterType)) + : Parameter(description), Callable(function), name(name) { } /** @@ -54,10 +54,11 @@ namespace command { virtual ~Option() { } /** - * + * \inheritdoc */ virtual void handle() { this->call(value); + used = true; } /** @@ -71,7 +72,7 @@ namespace command { * If no equal sign is after OptionName part, * std::invalid_argument exception with appropriate message is thrown * - * If conversion of OptionValue part to OptionType failed, + * If conversion of OptionValue part to ParameterType failed, * std::invalid_argument exception with appropriate message is thrown * * @param argv command line value against which test will be made. @@ -79,36 +80,52 @@ namespace command { * * @return If passed argv succesfully detected OptionName part as a * current option and its OptionValue part has been succesfully - * converted to OptionType, returns true and Option is set as used one. + * converted to ParameterType, returns true and Option is set as used one. * Otherwise returns false and can be used to check against next value. * - * @throw std::invalid_argument when OptionName part has no equal sign - * after itself - * @throw std::invalid_argument when OptionValue part failed conversion - * to OptionType + * @throw MissingOptionValue when OptionValue part is missing after + * equal sign + * @throw OptionFailedConversion when OptionValue part failed conversion + * to ParameterType */ virtual bool understand(const std::string & argv) { - if ((!used) && - (argv.find(name) == 0)) { - std::size_t pos = argv.find("="); + if (this->hasName(argv)) { + std::size_t pos = this->valuePosition(argv); + if (pos != name.size()) { - throw std::invalid_argument("Option: " + name + " requires value but no one has been provided"); + throw MissingOptionValue("Option: " + name + " requires value but no one has been provided"); } std::stringstream ss; - - ss << argv.substr(pos + 1); + ss << std::fixed << argv.substr(pos + 1); ss >> value; if (ss.fail()) { - throw std::invalid_argument("Value for option: " + name + " failed conversion to the required type"); + throw OptionFailedConversion("Option: " + name + " failed value conversion to the required type"); } - used = true; return true; } return false; } + + /** + * \inheritdoc + */ + virtual unsigned int valuePosition(const std::string & value) { + std::size_t pos = value.find("="); + + if ((this->hasName(value)) && (pos == std::string::npos)) { + throw OptionValueNotSpecified("Option: " + name + " requires value to be specified after equal sign, but no equal sign was found"); + } + + return pos; + } + + protected: + bool hasName(const std::string & argv) { + return argv.find(name) == 0; + } }; /** @@ -132,11 +149,7 @@ namespace command { /** * Current Option name */ - OptionName name; - - /** Variable indicating if current Option was already used or not */ - bool used = false; - + const OptionName name; public: /** * Default constructor. @@ -145,20 +158,16 @@ namespace command { * @param description Description of current Option * @param function Function used to handle current Option. */ - Option(std::string name, const std::string & description, void (*function)(void)) + Option(const std::string & name, const std::string & description, void (*function)(void)) : Parameter(description), Callable(function), name(name) { } - /** - * - */ - virtual ~Option() { } - /** * */ virtual void handle() { this->call(); + used = true; } /** @@ -177,13 +186,18 @@ namespace command { * used to check against next value. */ virtual bool understand(const std::string & argv) { - if ((!used) && - (argv == name)) { - used = true; + if (argv == name) { return true; } return false; } + + /** + * \inheritdoc + */ + virtual unsigned int valuePosition(const std::string & ) { + throw new std::invalid_argument(this->describe() + " is void Option, so it does not have value part"); + } }; }