virtual bool understand(const std::string & argv) {
std::stringstream ss;
- ss << argv;
+ ss << std::fixed << argv;
ss >> value;
if (!ss.fail()) {
#include <string>
#include <vector>
#include <typeinfo>
+#include <iostream>
#include "parameter.h"
-#include "exception/missingRequiredParameter.h"
+#include "grouped.h"
namespace command {
/**
* Main class for handling user passed parameters from command line.
*/
- class Command {
- protected:
- std::vector<Parameter *> parameters;
+ class Command : protected Grouped {
public:
/**
* Default constructor.
*
- * @param argc passed to the main function
- * @param argv passed to the main function
+ * @param argc from the main function
+ * @param argv from the main function
* @param params initializer_list containing Parameter handlers
* responsible for correctly handle user data.
*/
Command(unsigned int argc, char *argv[], std::initializer_list<Parameter *> params)
- : parameters(params) {
-
+ : Grouped(params, "Command") {
try {
- matchArguments(argc, argv);
+ for (unsigned int i = 1; i < argc; i++) {
+ this->understand(argv[i]);
+ }
+ handle();
}
catch(const std::invalid_argument & exception) {
releaseMemory();
~Command() {
releaseMemory();
}
- protected:
- /**
- * Matches user passed arguments with available parameter handlers.
- */
- void matchArguments(unsigned int argc, char *argv[]) {
- for (unsigned int i = 1; i < argc; i++) {
- for(Parameter *param : parameters) {
- if (!param->isUsed() && param->understand(argv[i])) {
- param->handle();
- break;
- }
- }
- }
- for(Parameter *param : parameters) {
- if (param->isRequired() && !param->isUsed()) {
- throw MissingRequiredParameter(param->describe() + " is required but it was not passed");
- }
- }
- }
-
- /**
- * Releases acquired memory
- */
- void releaseMemory() {
- for (Parameter * parameter : parameters) {
- if (parameter != NULL) {
- delete parameter;
- }
- }
- parameters.clear();
- parameters.shrink_to_fit();
- }
};
}
--- /dev/null
+#ifndef __COMMAND_GROUPED_H
+#define __COMMAND_GROUPED_H
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "parameter.h"
+#include "exception/missingRequiredParameter.h"
+
+namespace command {
+ /**
+ * Grouped Parameters decorator. Allows Parameters to understand be grouped
+ * together.
+ *
+ * Example usage:
+ * - ./myprog [ARGUMENT OPTION] [ARGUMENT OPTION] ...
+ */
+ class Grouped : public Parameter {
+ protected:
+ /**
+ * Parameters which will be treated as grouped together
+ */
+ std::vector<Parameter *> parameters;
+
+ std::vector<std::string> values;
+
+ std::vector<bool> understood;
+ std::vector<bool> all_used;
+
+ public:
+ /**
+ * Default constructor.
+ *
+ * @param params Parameters which will be treated as grouped together
+ */
+ Grouped(std::initializer_list<Parameter *> params, std::string description = "Grouped")
+ : Parameter(description), parameters(params) {
+ for (unsigned int i = 0; i < parameters.size(); i++) {
+ understood.push_back(false);
+ values.push_back("");
+ }
+ }
+
+ /**
+ * Default destructor. Releases allocated memory
+ */
+ virtual ~Grouped() {
+ releaseMemory();
+ }
+
+ /**
+ * Wrapper method around passed Parameter::handle().
+ *
+ * \inheritdoc
+ */
+ virtual void handle() {
+// std::cout << this->describe() << " handles" << "\n";
+// if (!isUsed()) {
+ for (unsigned int i = 0; i < parameters.size(); i++) {
+ Parameter *param = parameters[i];
+ if (understood[i] || param->hungryForValue()) {
+// std::cout << param->describe() << "=" << values[i] << "\n";
+ param->handle();
+ }
+ }
+// }
+ // @TODO: Nested required
+ for(Parameter *param : parameters) {
+ if (param->isRequired() && !param->isUsed()) {
+ throw MissingRequiredParameter(param->describe() + " is required");
+ }
+ }
+ }
+
+ /**
+ * Wrapper method around passed Parameter::understand()
+ *
+ * @param argv command line value against which test will be made
+ *
+ * \inheritdoc
+ */
+ virtual bool understand(const std::string & value) {
+// std::cout << "[+] Grouped [" << this->describe() << "]\n";
+
+ bool _understand = false;
+
+// std::cout << "GMD\n" ;
+ for (unsigned int i = 0; i < parameters.size(); i++) {
+ Parameter *param = parameters[i];
+
+// std::cout << " > Grouped:Param [" << param->describe() << ", " << value << "]\n";
+ if (!understood[i]) {
+ _understand = param->understand(value);
+ if (_understand) {
+// std::cout << " > Understood [" << param->describe() << ", " << value << "]\n";
+ understood[i] = _understand;
+ values[i] = value;
+ break;
+ }
+ }
+ }
+
+ bool all_understood = (understood.size() == parameters.size());
+ for (bool u : understood) {
+ all_understood &= u;
+ }
+
+// std::cout << this->describe() << " understand: " << std::boolalpha << all_understood << "\n";
+
+ return all_understood;
+ }
+
+ /**
+ * Indicates if current Parameter has been already used
+ *
+ * @return true if current Parameter has been already used. False otherwise.
+ */
+// virtual bool isUsed() {
+// if (!used) {
+// // bool used
+// for(Parameter *param : parameters) {
+// param->isUsed();
+// }
+// }
+// }
+
+ /**
+ * \inheritdoc
+ */
+ virtual bool hungryForValue() {
+ return true;
+ }
+
+ /**
+ * Wrapper method around passed Parameter::valuePosition().
+ *
+ * \inheritdoc
+ */
+ virtual unsigned int valuePosition(const std::string &) {
+ throw std::logic_error("Group does not have value part");
+ }
+
+ /**
+ * Releases acquired memory
+ */
+ void releaseMemory() {
+ for (Parameter * parameter : parameters) {
+ if (parameter != NULL) {
+ delete parameter;
+ }
+ }
+ parameters.clear();
+ parameters.shrink_to_fit();
+ }
+ };
+}
+
+#endif /* __COMMAND_GROUPED_H */
* \inheritdoc
*/
virtual bool understand(const std::string & value) {
- size_t start = parameter->valuePosition(value);
+ size_t start = 0;
size_t pos = 0;
bool _understand = true;
std::string prefix = "";
+ start = parameter->valuePosition(value);
+
+ if (start > value.size()) {
+ return false;
+ }
+
if (start > 0) {
prefix = value.substr(0, ++start);// always count: "="
}
values.push_back(prefix + value.substr(start, pos-start));
_understand &= parameter->understand(values.back());
start = pos + 1;
- } while ((pos != std::string::npos) && (start < value.size()));
+ if (!_understand) {
+ values.clear();
+ break;
+ }
+ } while ((pos != std::string::npos) && (start < value.size()));
return _understand;
}
};
}
-#endif /* __COMMAND_PARAMETER_H */
+#endif /* __COMMAND_MULTIVALUE_H */
* to ParameterType
*/
virtual bool understand(const std::string & argv) {
-
- if (argv.find(name) == 0) {
+ if (this->hasName(argv)) {
std::size_t pos = this->valuePosition(argv);
if (pos != name.size()) {
}
std::stringstream ss;
- ss << argv.substr(pos + 1);
+ ss << std::fixed << argv.substr(pos + 1);
ss >> value;
if (ss.fail()) {
- throw OptionFailedConversion("Value for option: " + name + " failed conversion to the required type");
+ throw OptionFailedConversion("Option: " + name + " failed value conversion to the required type");
}
return true;
virtual unsigned int valuePosition(const std::string & value) {
std::size_t pos = value.find("=");
- if (pos == std::string::npos) {
- throw OptionValueNotSpecified("Option: " + name + " requires value to be specified using equal sign");
+ 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;
+ }
};
/**
#define __COMMAND_PARAMETER_H
#include <string>
+#include <sstream>
#include "descriptive.h"
#include "callable.h"
return used;
}
+ /**
+ */
+ virtual bool hungryForValue() {
+ return false;
+ }
+
/**
* @return position where value starts in passed string
*/
};
}
-#endif /* __COMMAND_PARAMETER_H */
+#endif /* __COMMAND_REQUIRED_H */
#include "argument.h"
#include "required.h"
#include "multiValue.h"
+#include "grouped.h"
#include "command.h"
using namespace command;
int main(int argc, char *argv[]) {
try {
Command command(argc, argv, {
-// new Argument<std::string>("File path", [](std::string value)->void { std::cout << "Hello from lambda " << value << std::endl; }),
- new Required(new MultiValue("-", new Argument<bool>("Input values", argument_function))),
- new MultiValue(",", new Option<std::string>("f", "Optional file", option_function)),
+ new Grouped({
+ new Required(new MultiValue("-", new Argument<bool>("Input values", argument_function))),
+ new MultiValue(",", new Option<std::string>("f", "Optional file", option_function))
+ }),
new Option<void>("h", "Help", void_function)
});
-
}
catch(const std::exception & e) {
std::cout << e.what() << std::endl;