|
@@ -5,6 +5,8 @@
|
|
|
#include <string>
|
|
#include <string>
|
|
|
#include <vector>
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
+#include "program_args/any.h"
|
|
|
|
|
+
|
|
|
namespace program {
|
|
namespace program {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -19,6 +21,9 @@ struct LongArg {
|
|
|
std::string str;
|
|
std::string str;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+constexpr struct usage_on_error_t {
|
|
|
|
|
+} usage_on_error;
|
|
|
|
|
+
|
|
|
template <typename Impl> class Arguments {
|
|
template <typename Impl> class Arguments {
|
|
|
private:
|
|
private:
|
|
|
using option_id = std::string;
|
|
using option_id = std::string;
|
|
@@ -30,12 +35,25 @@ private:
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
Arguments() = default;
|
|
Arguments() = default;
|
|
|
- Arguments(int argc, char const * const * const argv);
|
|
|
|
|
|
|
+ Arguments(int argc, char const * const * const argv)
|
|
|
|
|
+ : Arguments(argc, argv, (void const *)nullptr) {}
|
|
|
|
|
|
|
|
std::vector<std::string> args() const {
|
|
std::vector<std::string> args() const {
|
|
|
return {arguments.begin() + argument_names.size(), arguments.end()};
|
|
return {arguments.begin() + argument_names.size(), arguments.end()};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+protected:
|
|
|
|
|
+ template <typename T> Arguments(T const * parent) : parent_(parent) {}
|
|
|
|
|
+ template <typename T>
|
|
|
|
|
+ Arguments(int argc, char const * const * const argv, T const * parent);
|
|
|
|
|
+
|
|
|
|
|
+ template <typename T> T const * parent() const { return parent_.get<T>(); }
|
|
|
|
|
+
|
|
|
|
|
+ template <typename Tuple, typename Default, size_t... Is, typename... Parents>
|
|
|
|
|
+ int invoke_action(Default const & default_action, Tuple const & tuple,
|
|
|
|
|
+ std::index_sequence<Is...>,
|
|
|
|
|
+ Parents const &... parents) const;
|
|
|
|
|
+
|
|
|
protected:
|
|
protected:
|
|
|
/**
|
|
/**
|
|
|
* @brief Define an "action"/"subcommand"/"verb" to be executed. An example of
|
|
* @brief Define an "action"/"subcommand"/"verb" to be executed. An example of
|
|
@@ -137,26 +155,42 @@ private:
|
|
|
// A helper for what limited introspection is required for handling actions in
|
|
// A helper for what limited introspection is required for handling actions in
|
|
|
// test
|
|
// test
|
|
|
friend struct ArgumentTestHelper;
|
|
friend struct ArgumentTestHelper;
|
|
|
|
|
+ template <typename> friend class Arguments;
|
|
|
friend int main(int, char const * const *);
|
|
friend int main(int, char const * const *);
|
|
|
|
|
|
|
|
|
|
+ operator bool() const { return primed_; }
|
|
|
|
|
+
|
|
|
|
|
+ template <typename... Parents> int invoke(Parents const &... parents) const {
|
|
|
|
|
+ return typed_main(parents..., static_cast<Impl const &>(*this));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ template <typename T>
|
|
|
|
|
+ std::shared_ptr<T> make_action(std::string const & name) const {
|
|
|
|
|
+ if (action_name_ != name) { return nullptr; }
|
|
|
|
|
+ auto ptr = make_action_(static_cast<Impl const &>(*this));
|
|
|
|
|
+ return std::static_pointer_cast<T>(ptr);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private:
|
|
private:
|
|
|
- using main_callback_t = std::function<int(Impl const &)>;
|
|
|
|
|
- using make_hook_t =
|
|
|
|
|
- std::function<main_callback_t(size_t, char const * const *)>;
|
|
|
|
|
|
|
+ using make_action_t = std::function<std::shared_ptr<void>(Impl const &)>;
|
|
|
|
|
+ using action_hook_t =
|
|
|
|
|
+ std::function<make_action_t(size_t, char const * const *)>;
|
|
|
// Metadata variables
|
|
// Metadata variables
|
|
|
bool primed_{false};
|
|
bool primed_{false};
|
|
|
|
|
+ detail::Any parent_;
|
|
|
std::string rest_name;
|
|
std::string rest_name;
|
|
|
std::map<option_id, std::string> argument_descriptions;
|
|
std::map<option_id, std::string> argument_descriptions;
|
|
|
std::map<size_t, option_id> argument_names;
|
|
std::map<size_t, option_id> argument_names;
|
|
|
std::map<option_id, std::string> option_descriptions;
|
|
std::map<option_id, std::string> option_descriptions;
|
|
|
std::map<std::string, option_id> option_names;
|
|
std::map<std::string, option_id> option_names;
|
|
|
std::set<option_id> flag_names;
|
|
std::set<option_id> flag_names;
|
|
|
- std::map<std::string, make_hook_t> actions;
|
|
|
|
|
|
|
+ std::map<std::string, action_hook_t> actions;
|
|
|
|
|
+ std::string action_name_{""};
|
|
|
|
|
+ make_action_t make_action_{nullptr};
|
|
|
std::map<std::string, std::string> action_descriptions;
|
|
std::map<std::string, std::string> action_descriptions;
|
|
|
|
|
|
|
|
// Data/Output variables
|
|
// Data/Output variables
|
|
|
std::string program;
|
|
std::string program;
|
|
|
- main_callback_t main_callback{nullptr};
|
|
|
|
|
constexpr static size_t const no_optional_args{~0ul};
|
|
constexpr static size_t const no_optional_args{~0ul};
|
|
|
size_t optional_from{no_optional_args};
|
|
size_t optional_from{no_optional_args};
|
|
|
std::vector<std::string> arguments;
|
|
std::vector<std::string> arguments;
|
|
@@ -218,31 +252,37 @@ template <typename B, typename V>
|
|
|
struct Arguments<Impl>::WithDefault {
|
|
struct Arguments<Impl>::WithDefault {
|
|
|
B impl;
|
|
B impl;
|
|
|
V default_value;
|
|
V default_value;
|
|
|
- template <typename T> operator T() const {
|
|
|
|
|
- if (impl) { return impl; }
|
|
|
|
|
- if constexpr (std::is_invocable_r<T, V>{}) {
|
|
|
|
|
- return T(default_value());
|
|
|
|
|
- } else {
|
|
|
|
|
- return T{default_value};
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ template <typename T> operator T() const;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#include "arguments_impl.hpp"
|
|
#include "arguments_impl.hpp"
|
|
|
|
|
|
|
|
-template <typename Args, typename Action>
|
|
|
|
|
-int typed_main(Args const &, Action const &);
|
|
|
|
|
|
|
+template <typename Args, typename... Actions>
|
|
|
|
|
+int typed_main(Args const &, Actions const &...);
|
|
|
|
|
|
|
|
-#define TYPED_MAIN(tname) \
|
|
|
|
|
- int typed_main(tname const & args); \
|
|
|
|
|
|
|
+#define PROGRAM_ARGS_INVOKE_WITH_DEFAULT(default, ...) \
|
|
|
|
|
+ template <typename... Parents> \
|
|
|
|
|
+ int invoke(Parents const &... parents) const { \
|
|
|
|
|
+ return invoke_action(default, program::actions(__VA_ARGS__), \
|
|
|
|
|
+ program::count(__VA_ARGS__), parents..., *this); \
|
|
|
|
|
+ } \
|
|
|
|
|
+ using Arguments::Arguments
|
|
|
|
|
+
|
|
|
|
|
+#define PROGRAM_ARGS_INVOKE(...) \
|
|
|
|
|
+ PROGRAM_ARGS_INVOKE_WITH_DEFAULT(program::usage_on_error, ##__VA_ARGS__)
|
|
|
|
|
+
|
|
|
|
|
+#define PROGRAM_ARGS_MAIN(tname) \
|
|
|
int main(int argc, char const * const * const argv) try { \
|
|
int main(int argc, char const * const * const argv) try { \
|
|
|
- tname args(argc, argv); \
|
|
|
|
|
- return (args.main_callback) ? args.main_callback(args) : typed_main(args); \
|
|
|
|
|
|
|
+ return tname(argc, argv).invoke(); \
|
|
|
} catch (program::ProgramArgumentsError const & pae) { \
|
|
} catch (program::ProgramArgumentsError const & pae) { \
|
|
|
std::cerr << "Error in program argument handling: " << pae.what() << "\n"; \
|
|
std::cerr << "Error in program argument handling: " << pae.what() << "\n"; \
|
|
|
- } \
|
|
|
|
|
- int typed_main(tname const & args)
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+#define TYPED_MAIN(tname) \
|
|
|
|
|
+ PROGRAM_ARGS_MAIN(tname) \
|
|
|
|
|
+ template <> int typed_main(tname const & args)
|
|
|
|
|
|
|
|
#define PROGRAM_DEFER(...) [this]() { return __VA_ARGS__; }
|
|
#define PROGRAM_DEFER(...) [this]() { return __VA_ARGS__; }
|