|
|
@@ -1,15 +1,17 @@
|
|
|
#pragma once
|
|
|
|
|
|
-#include "options.hpp"
|
|
|
-
|
|
|
#include <utility>
|
|
|
|
|
|
+#include "arguments.h"
|
|
|
+#include "exception.h"
|
|
|
+#include "utilities.h"
|
|
|
+
|
|
|
namespace program {
|
|
|
|
|
|
template <typename Impl>
|
|
|
template <typename T>
|
|
|
Arguments<Impl>::Option::operator T() const {
|
|
|
- return (*this) ? self->options.at(name) : T();
|
|
|
+ return (*this) ? convert<T>(self->options.at(name)) : T();
|
|
|
}
|
|
|
|
|
|
template <typename Impl>
|
|
|
@@ -23,16 +25,6 @@ auto Arguments<Impl>::Option::operator=(T &&value) {
|
|
|
return WithDefault<Option, T>{*this, std::forward<T>(value)};
|
|
|
}
|
|
|
|
|
|
-inline std::string join(std::string const &tok,
|
|
|
- std::vector<std::string> const &data) {
|
|
|
- std::string accum = data.empty() ? "" : data.front();
|
|
|
- for (size_t i = 1; i < data.size(); ++i) {
|
|
|
- accum += tok;
|
|
|
- accum += data[i];
|
|
|
- }
|
|
|
- return accum;
|
|
|
-}
|
|
|
-
|
|
|
template <typename Impl>
|
|
|
bool Arguments<Impl>::Option::primed() const {
|
|
|
if (self->primed_) { return true; }
|
|
|
@@ -41,7 +33,9 @@ bool Arguments<Impl>::Option::primed() const {
|
|
|
aliases.emplace_back(std::string{'-', abbrev});
|
|
|
}
|
|
|
for (auto &alias : aliases) {
|
|
|
- self->option_name_mapping.emplace(alias, name);
|
|
|
+ if (!self->option_name_mapping.emplace(alias, name).second) {
|
|
|
+ throw ArgumentStructureError("Duplicate option string", alias);
|
|
|
+ }
|
|
|
}
|
|
|
self->option_descriptions.emplace(join("/", aliases), description);
|
|
|
return false;
|
|
|
@@ -54,12 +48,16 @@ namespace program {
|
|
|
template <typename Impl>
|
|
|
template <typename T>
|
|
|
Arguments<Impl>::Positional::operator T() const {
|
|
|
- return (*this) ? self->arguments.at(index) : T();
|
|
|
+ return (*this) ? convert<T>(self->arguments.at(index)) : T();
|
|
|
}
|
|
|
|
|
|
template <typename Impl>
|
|
|
Arguments<Impl>::Positional::operator bool() const {
|
|
|
- return primed(); // TODO(samjaffe): Existance check?
|
|
|
+ bool const good = primed();
|
|
|
+ if (good && self->arguments.size() <= index) {
|
|
|
+ throw IllegalPositionError("No argument provided", index);
|
|
|
+ }
|
|
|
+ return good;
|
|
|
}
|
|
|
|
|
|
template <typename Impl>
|
|
|
@@ -75,11 +73,11 @@ bool Arguments<Impl>::Positional::primed() const {
|
|
|
if (is_optional) {
|
|
|
self->optional_from = std::min(self->optional_from, index);
|
|
|
} else if (self->optional_from < index) {
|
|
|
- throw std::logic_error{
|
|
|
- "Cannot have required positional named '" + name +
|
|
|
- "' after optional positionals"};
|
|
|
+ throw ArgumentStructureError{"Required positional after optional", name};
|
|
|
+ }
|
|
|
+ if (!self->argument_names.emplace(index, name).second) {
|
|
|
+ throw IllegalPositionError("Duplicate positional", index);
|
|
|
}
|
|
|
- self->argument_names.emplace(index, name);
|
|
|
self->positional_descriptions.emplace(name, description);
|
|
|
return false;
|
|
|
}
|
|
|
@@ -94,7 +92,8 @@ Arguments<Impl>::Arguments(int argc, char const * const * const argv) {
|
|
|
Impl generator;
|
|
|
*this = static_cast<Arguments const&>(generator);
|
|
|
if (argument_names.rbegin()->first != argument_names.size() - 1) {
|
|
|
- throw std::logic_error{"Jagged arguments are not supported"};
|
|
|
+ throw IllegalPositionError("Higher positional than number recorded",
|
|
|
+ argument_names.rbegin()->first);
|
|
|
}
|
|
|
|
|
|
primed_ = true;
|
|
|
@@ -102,13 +101,14 @@ Arguments<Impl>::Arguments(int argc, char const * const * const argv) {
|
|
|
for (size_t i = 1; i < argc; ++i) {
|
|
|
if (arg_equals("--help")) {
|
|
|
usage();
|
|
|
- std::exit(0);
|
|
|
+ std::exit(0); // TODO: ???
|
|
|
} else if (arg_equals("--")) {
|
|
|
+ // TODO: Special arguments store for passthroughs
|
|
|
arguments.insert(arguments.end(), &argv[i+1], &argv[argc]);
|
|
|
- i = argc;
|
|
|
+ break;
|
|
|
} else if (argv[i][0] == '-') {
|
|
|
- // TODO(samjaffe): Arity
|
|
|
- options.emplace(option_name_mapping.at(argv[i]), argv[i+1]);
|
|
|
+ // TODO: Arity
|
|
|
+ options[option_name_mapping.at(argv[i])].emplace_back(argv[i+1]);
|
|
|
++i;
|
|
|
} else {
|
|
|
arguments.emplace_back(argv[i]);
|
|
|
@@ -136,10 +136,17 @@ void Arguments<Impl>::usage() const {
|
|
|
}
|
|
|
|
|
|
template <typename Impl>
|
|
|
-auto Arguments<Impl>::option(std::string const &name, std::string const &description) {
|
|
|
+auto Arguments<Impl>::option(std::string const &name,
|
|
|
+ std::string const &description) {
|
|
|
return Option{this, name, 0, description};
|
|
|
}
|
|
|
|
|
|
+template <typename Impl>
|
|
|
+auto Arguments<Impl>::option(std::string const &name, char abbrev,
|
|
|
+ std::string const &description) {
|
|
|
+ return Option{this, name, abbrev, description};
|
|
|
+}
|
|
|
+
|
|
|
template <typename Impl>
|
|
|
auto Arguments<Impl>::argument(size_t index, std::string const &name,
|
|
|
std::string const &description) {
|
|
|
@@ -147,3 +154,4 @@ auto Arguments<Impl>::argument(size_t index, std::string const &name,
|
|
|
}
|
|
|
|
|
|
}
|
|
|
+#undef arg_equals
|