#include <stdexcept>
#include "parameter.h"
+#include "exception/missingOptionValue.h"
+#include "exception/optionFailedConversion.h"
+#include "exception/optionValueNotSpecified.h"
namespace command {
/**
* 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<typename OptionType>
+ template<typename ParameterType>
class Option
- : public Parameter, public Callable<OptionType> {
+ : public Parameter, public Callable<ParameterType> {
public:
typedef std::string OptionName;
protected:
/**
* Current Option value
*/
- OptionType value;
+ ParameterType value;
public:
/**
* @param description Description of current Option
* @param function Function used to handle current Option.
*/
- Option(const std::string & name, const std::string & description, void (*function)(OptionType))
- : Parameter(description), Callable<OptionType>(function), name(name) {
+ Option(const std::string & name, const std::string & description, std::function<void(ParameterType)> function)
+ : Parameter(description), Callable<ParameterType>(function), name(name) {
}
/**
virtual ~Option() { }
/**
- *
+ * \inheritdoc
*/
virtual void handle() {
this->call(value);
+ used = true;
}
/**
* 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.
*
* @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)
- throw(std::invalid_argument) {
-
- if ((!isUsed()) && (argv.find(name) == 0)) {
- std::size_t pos = argv.find("=");
+ virtual bool understand(const std::string & argv) {
+ 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 >> value;// memory leak? when uncommented and exception is
- // thrown, valgrind shows e.g.:
- // possibly lost: 380 bytes in 7 blocks
+ 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;
+ }
};
/**
* @param description Description of current Option
* @param function Function used to handle current Option.
*/
- Option(const std::string & name, const std::string & description, void (*function)(void))
+ Option(const std::string & name, const std::string & description, std::function<void(void)> function)
: Parameter(description), Callable<void>(function), name(name) {
}
*/
virtual void handle() {
this->call();
+ used = true;
}
/**
* used to check against next value.
*/
virtual bool understand(const std::string & argv) {
- if ((!isUsed()) &&
- (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");
+ }
};
}