chore: separate definitions from declarations for argument parser where possible.

This commit is contained in:
2026-03-15 23:32:18 +04:00
parent 7e2c09cbf9
commit c7304aa36e
5 changed files with 428 additions and 336 deletions

View File

@@ -5,361 +5,232 @@
#ifndef ARGUMENT_PARSER_HPP #ifndef ARGUMENT_PARSER_HPP
#define ARGUMENT_PARSER_HPP #define ARGUMENT_PARSER_HPP
#include <traits.hpp> #include <any>
#include <base_convention.hpp>
#include <atomic> #include <atomic>
#include <base_convention.hpp>
#include <functional> #include <functional>
#include <initializer_list> #include <initializer_list>
#include <iostream> #include <memory>
#include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <traits.hpp>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <any>
#include <ranges>
namespace argument_parser { namespace argument_parser {
class action_base { class action_base {
public: public:
virtual ~action_base() = default; virtual ~action_base() = default;
[[nodiscard]] virtual bool expects_parameter() const = 0; [[nodiscard]] virtual bool expects_parameter() const = 0;
virtual void invoke() const = 0; virtual void invoke() const = 0;
virtual void invoke_with_parameter(const std::string& param) const = 0; virtual void invoke_with_parameter(const std::string &param) const = 0;
[[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0; [[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0;
}; };
template <typename T> template <typename T> class parametered_action : public action_base {
class parametered_action : public action_base { public:
public: explicit parametered_action(std::function<void(const T &)> const &handler) : handler(handler) {}
explicit parametered_action(std::function<void(const T&)> const& handler) : handler(handler) {} using parameter_type = T;
void invoke(const T &arg) const {
using parameter_type = T; handler(arg);
}
void invoke(const T& arg) const {
handler(arg);
}
[[nodiscard]] bool expects_parameter() const override { return true; } [[nodiscard]] bool expects_parameter() const override {
return true;
void invoke() const override { }
throw std::runtime_error("Parametered action requires a parameter");
}
void invoke_with_parameter(const std::string& param) const override {
T parsed_value = parsing_traits::parser_trait<T>::parse(param);
invoke(parsed_value);
}
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
return std::make_unique<parametered_action<T>>(handler);
}
private: void invoke() const override {
std::function<void(const T&)> handler; throw std::runtime_error("Parametered action requires a parameter");
}; }
class non_parametered_action : public action_base { void invoke_with_parameter(const std::string &param) const override {
public: T parsed_value = parsing_traits::parser_trait<T>::parse(param);
explicit non_parametered_action(std::function<void()> const& handler) : handler(handler) {} invoke(parsed_value);
}
void invoke() const override {
handler();
}
[[nodiscard]] bool expects_parameter() const override { return false; } [[nodiscard]] std::unique_ptr<action_base> clone() const override {
return std::make_unique<parametered_action<T>>(handler);
void invoke_with_parameter(const std::string& param) const override { }
invoke();
}
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
return std::make_unique<non_parametered_action>(handler);
}
private: private:
std::function<void()> handler; std::function<void(const T &)> handler;
}; };
class base_parser; class non_parametered_action : public action_base {
public:
explicit non_parametered_action(std::function<void()> const &handler) : handler(handler) {}
class argument { void invoke() const override {
public: handler();
argument() : id(0), name(), action(std::make_unique<non_parametered_action>([](){})), required(false), invoked(false) {} }
template <typename ActionType> [[nodiscard]] bool expects_parameter() const override {
argument(const int id, std::string name, ActionType const& action) return false;
: id(id), name(std::move(name)), action(action.clone()), required(false), invoked(false) {} }
argument(const argument& other) void invoke_with_parameter(const std::string &param) const override {
: id(other.id), name(other.name), action(other.action->clone()), invoke();
required(other.required), invoked(other.invoked), help_text(other.help_text) {} }
argument& operator=(const argument& other) { [[nodiscard]] std::unique_ptr<action_base> clone() const override {
if (this != &other) { return std::make_unique<non_parametered_action>(handler);
id = other.id; }
name = other.name;
action = other.action->clone();
required = other.required;
invoked = other.invoked;
help_text = other.help_text;
}
return *this;
}
argument(argument&& other) noexcept = default; private:
argument& operator=(argument&& other) noexcept = default; std::function<void()> handler;
};
[[nodiscard]] bool is_required() const { return required; } class base_parser;
[[nodiscard]] std::string get_name() const { return name; }
[[nodiscard]] bool is_invoked() const { return invoked; }
[[nodiscard]] bool expects_parameter() const { class argument {
return action->expects_parameter(); public:
} argument();
private: template <typename ActionType>
void set_required(bool val) { required = val; } argument(const int id, std::string name, ActionType const &action)
void set_invoked(bool val) { invoked = val; } : id(id), name(std::move(name)), action(action.clone()), required(false), invoked(false) {}
void set_help_text(std::string const& text) { help_text = text; }
friend class base_parser; argument(const argument &other);
argument &operator=(const argument &other);
argument(argument &&other) noexcept = default;
argument &operator=(argument &&other) noexcept = default;
int id; [[nodiscard]] bool is_required() const;
std::string name; [[nodiscard]] std::string get_name() const;
std::unique_ptr<action_base> action; [[nodiscard]] bool is_invoked() const;
bool required; [[nodiscard]] bool expects_parameter() const;
bool invoked; [[nodiscard]] std::string get_help_text() const;
std::string help_text;
};
namespace helpers { private:
template<typename T> void set_required(bool val);
static parametered_action<T> make_parametered_action(std::function<void(const T&)> const& function) { void set_invoked(bool val);
return parametered_action<T>(function); void set_help_text(std::string const &text);
}
static non_parametered_action make_non_parametered_action(std::function<void()> const& function) { friend class base_parser;
return non_parametered_action(function);
}
}
class base_parser { int id;
public: std::string name;
template <typename T> std::unique_ptr<action_base> action;
void add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, parametered_action<T> const& action, bool required) { bool required;
base_add_argument(short_arg, long_arg, help_text, action, required); bool invoked;
} std::string help_text;
};
template<typename T> namespace helpers {
void add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, bool required) { template <typename T>
base_add_argument<T>(short_arg, long_arg, help_text, required); static parametered_action<T> make_parametered_action(std::function<void(const T &)> const &function) {
} return parametered_action<T>(function);
}
void add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, non_parametered_action const& action, bool required) { static non_parametered_action make_non_parametered_action(std::function<void()> const &function) {
base_add_argument(short_arg, long_arg, help_text, action, required); return non_parametered_action(function);
} }
} // namespace helpers
void add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, bool required) { class base_parser {
base_add_argument<void>(short_arg, long_arg, help_text, required); public:
} template <typename T>
void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
parametered_action<T> const &action, bool required) {
base_add_argument(short_arg, long_arg, help_text, action, required);
}
void on_complete(std::function<void(base_parser const&)> const& action) { template <typename T>
on_complete_events.emplace_back(action); void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
} bool required) {
base_add_argument<T>(short_arg, long_arg, help_text, required);
}
template<typename T> void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
std::optional<T> get_optional(std::string const& arg) const { non_parametered_action const &action, bool required) {
auto id = find_argument_id(arg); base_add_argument(short_arg, long_arg, help_text, action, required);
if (id.has_value()) { }
auto value = stored_arguments.find(id.value());
if (value != stored_arguments.end() && value->second.has_value()) return std::any_cast<T>(value->second);
}
return std::nullopt;
}
[[nodiscard]] std::string build_help_text(std::initializer_list<conventions::convention const* const> convention_types) const { void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
std::stringstream ss; bool required) {
ss << "Usage: " << program_name << " [OPTIONS]...\n"; base_add_argument<void>(short_arg, long_arg, help_text, required);
}
for (auto const& [id, arg] : argument_map) {
auto short_arg = reverse_short_arguments.at(id);
auto long_arg = reverse_long_arguments.at(id);
ss << "\t";
ss << "-" << short_arg << ", --" << long_arg;
ss << "\t\t" << arg.help_text << "\n";
}
return ss.str();
}
argument& get_argument(conventions::parsed_argument const& arg) { void on_complete(std::function<void(base_parser const &)> const &action);
if (arg.first == conventions::argument_type::LONG) { template <typename T> std::optional<T> get_optional(std::string const &arg) const {
auto long_pos = long_arguments.find(arg.second); auto id = find_argument_id(arg);
if (long_pos != long_arguments.end()) return argument_map.at(long_pos->second); if (id.has_value()) {
} else if (arg.first == conventions::argument_type::SHORT) { auto value = stored_arguments.find(id.value());
auto short_pos = short_arguments.find(arg.second); if (value != stored_arguments.end() && value->second.has_value())
if (short_pos != short_arguments.end()) return argument_map.at(short_pos->second); return std::any_cast<T>(value->second);
} else if (arg.first == conventions::argument_type::INTERCHANGABLE) { }
auto long_pos = long_arguments.find(arg.second); return std::nullopt;
if (long_pos != long_arguments.end()) return argument_map.at(long_pos->second); }
auto short_pos = short_arguments.find(arg.second);
if (short_pos != short_arguments.end()) return argument_map.at(short_pos->second);
}
throw std::runtime_error("Unknown argument: " + arg.second);
}
[[nodiscard]] std::optional<int> find_argument_id(std::string const& arg) const { [[nodiscard]] std::string
auto long_pos = long_arguments.find(arg); build_help_text(std::initializer_list<conventions::convention const *const> convention_types) const;
auto short_post = short_arguments.find(arg); argument &get_argument(conventions::parsed_argument const &arg);
[[nodiscard]] std::optional<int> find_argument_id(std::string const &arg) const;
void handle_arguments(std::initializer_list<conventions::convention const *const> convention_types);
void display_help(std::initializer_list<conventions::convention const *const> convention_types) const;
if (long_pos != long_arguments.end()) return long_pos->second; protected:
if (short_post != short_arguments.end()) return short_post->second; base_parser() = default;
return std::nullopt;
}
void handle_arguments(std::initializer_list<conventions::convention const* const> convention_types) {
for (auto it = parsed_arguments.begin(); it != parsed_arguments.end(); ++it) {
std::stringstream error_stream;
bool arg_correctly_handled = false;
for (auto const& convention_type : convention_types) { std::string program_name;
auto extracted = convention_type->get_argument(*it); std::vector<std::string> parsed_arguments;
if (extracted.first == conventions::argument_type::ERROR) {
error_stream << "Convention \"" << convention_type->name() << "\" failed with: " << extracted.second << "\n";
continue;
}
try { private:
argument& corresponding_argument = get_argument(extracted); void assert_argument_not_exist(std::string const &short_arg, std::string const &long_arg) const;
static void set_argument_status(bool is_required, std::string const &help_text, argument &arg);
if (corresponding_argument.expects_parameter()) { void place_argument(int id, argument const &arg, std::string const &short_arg, std::string const &long_arg);
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
throw std::runtime_error("expected value for argument " + extracted.second);
}
auto value_raw = convention_type->requires_next_token() ? *(++it) : convention_type->extract_value(*it);
corresponding_argument.action->invoke_with_parameter(value_raw);
} else {
corresponding_argument.action->invoke();
}
corresponding_argument.set_invoked(true); template <typename ActionType>
arg_correctly_handled = true; void base_add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
break; // Convention succeeded, move to the next argument token ActionType const &action, bool required) {
assert_argument_not_exist(short_arg, long_arg);
int id = id_counter.fetch_add(1);
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
}
} catch (const std::runtime_error& e) { template <typename StoreType = void>
error_stream << "Convention \"" << convention_type->name() << "\" failed with: " << e.what() << "\n"; void base_add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
} bool required) {
} assert_argument_not_exist(short_arg, long_arg);
int id = id_counter.fetch_add(1);
if constexpr (std::is_same_v<StoreType, void>) {
auto action =
helpers::make_non_parametered_action([id, this] { stored_arguments[id] = std::any{true}; });
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
} else {
auto action = helpers::make_parametered_action<StoreType>(
[id, this](StoreType const &value) { stored_arguments[id] = std::any{value}; });
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
}
}
if (!arg_correctly_handled) { void check_for_required_arguments(std::initializer_list<conventions::convention const *const> convention_types);
throw std::runtime_error("All trials for argument: \n\t\"" + *it + "\"\n failed with: \n" + error_stream.str()); void fire_on_complete_events() const;
}
}
check_for_required_arguments(convention_types);
fire_on_complete_events();
}
void display_help(std::initializer_list<conventions::convention const* const> convention_types) const { inline static std::atomic_int id_counter = 0;
std::cout << build_help_text(convention_types);
}
protected: std::unordered_map<int, std::any> stored_arguments;
base_parser() = default; std::unordered_map<int, argument> argument_map;
std::unordered_map<std::string, int> short_arguments;
std::unordered_map<int, std::string> reverse_short_arguments;
std::unordered_map<std::string, int> long_arguments;
std::unordered_map<int, std::string> reverse_long_arguments;
std::string program_name; std::list<std::function<void(base_parser const &)>> on_complete_events;
std::vector<std::string> parsed_arguments;
private: friend class linux_parser;
void assert_argument_not_exist(std::string const& short_arg, std::string const& long_arg) const { friend class windows_parser;
if (short_arguments.contains(short_arg) || long_arguments.contains(long_arg)) { friend class macos_parser;
throw std::runtime_error("The key already exists!"); friend class fake_parser;
} };
} } // namespace argument_parser
static void set_argument_status(bool is_required, std::string const& help_text, argument& arg) {
arg.set_required(is_required);
arg.set_help_text(help_text);
}
void place_argument(int id, argument const& arg, std::string const& short_arg, std::string const& long_arg) {
argument_map[id] = arg;
short_arguments[short_arg] = id;
reverse_short_arguments[id] = short_arg;
long_arguments[long_arg] = id;
reverse_long_arguments[id] = long_arg;
}
template <typename ActionType>
void base_add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, ActionType const& action, bool required) {
assert_argument_not_exist(short_arg, long_arg);
int id = id_counter.fetch_add(1);
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
}
template<typename StoreType = void>
void base_add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, bool required) {
assert_argument_not_exist(short_arg, long_arg);
int id = id_counter.fetch_add(1);
if constexpr (std::is_same_v<StoreType, void>) {
auto action = helpers::make_non_parametered_action([id, this] { stored_arguments[id] = std::any{ true }; });
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
} else {
auto action = helpers::make_parametered_action<StoreType>([id, this](StoreType const& value) { stored_arguments[id] = std::any{ value }; });
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
}
}
void check_for_required_arguments(std::initializer_list<conventions::convention const* const> convention_types) {
std::vector<std::pair<std::string, std::string>> required_args;
for (const auto &arg: argument_map | std::views::values) {
if (arg.is_required() and not arg.is_invoked()) {
required_args.emplace_back<std::pair<std::string, std::string>>({
reverse_short_arguments[arg.id],
reverse_long_arguments[arg.id]
});
}
}
if (not required_args.empty()) {
std::cerr << "These arguments were expected but not provided: ";
for (auto const& [s, l] : required_args) {
std::cerr << "[-" << s << ", --" << l << "] ";
}
std::cerr << "\n";
display_help(convention_types);
}
}
void fire_on_complete_events() const {
for(auto const& event : on_complete_events) {
event(*this);
}
}
inline static std::atomic_int id_counter = 0;
std::unordered_map<int, std::any> stored_arguments;
std::unordered_map<int, argument> argument_map;
std::unordered_map<std::string, int> short_arguments;
std::unordered_map<int, std::string> reverse_short_arguments;
std::unordered_map<std::string, int> long_arguments;
std::unordered_map<int, std::string> reverse_long_arguments;
std::list<std::function<void(base_parser const&)>> on_complete_events;
friend class linux_parser;
friend class windows_parser;
friend class macos_parser;
friend class fake_parser;
};
}
#endif // ARGUMENT_PARSER_HPP #endif // ARGUMENT_PARSER_HPP

View File

@@ -9,34 +9,18 @@
#include <string> #include <string>
namespace argument_parser { namespace argument_parser {
class macos_parser : public base_parser { class macos_parser : public base_parser {
public: public:
macos_parser() { macos_parser();
const int argc = *_NSGetArgc(); };
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
program_name = (argv[0]);
for (int i = 1; i < argc; ++i) {
if (argv[i] != nullptr) parsed_arguments.emplace_back(argv[i]);
}
}
}
};
namespace v2 { namespace v2 {
class macos_parser : public v2::base_parser { class macos_parser : public v2::base_parser {
public: public:
macos_parser() { macos_parser();
const int argc = *_NSGetArgc(); };
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) { } // namespace v2
set_program_name(argv[0]); } // namespace argument_parser
for (int i = 1; i < argc; ++i) {
if (argv[i] != nullptr) ref_parsed_args().emplace_back(argv[i]);
}
}
}
};
}
}
#endif #endif
#endif #endif

View File

@@ -1,4 +1,3 @@
#include "macos_parser.hpp"
#include <string> #include <string>
#define ALLOW_DASH_FOR_WINDOWS 0 #define ALLOW_DASH_FOR_WINDOWS 0
@@ -8,8 +7,10 @@
#include <iostream> #include <iostream>
#include <parser_v2.hpp> #include <parser_v2.hpp>
#include <regex> #include <regex>
#include <sstream>
#include <vector> #include <vector>
struct Point { struct Point {
int x, y; int x, y;
}; };
@@ -35,7 +36,7 @@ template <> struct argument_parser::parsing_traits::parser_trait<std::regex> {
template <> struct argument_parser::parsing_traits::parser_trait<std::vector<int>> { template <> struct argument_parser::parsing_traits::parser_trait<std::vector<int>> {
static std::vector<int> parse(const std::string &input) { static std::vector<int> parse(const std::string &input) {
std::vector<int> result; std::vector<int> result;
std::stringstream ss(input); std::stringstream ss{input};
std::string item; std::string item;
while (std::getline(ss, item, ',')) { while (std::getline(ss, item, ',')) {
result.push_back(std::stoi(item)); result.push_back(std::stoi(item));

View File

@@ -0,0 +1,205 @@
#include "argument_parser.hpp"
#include <iostream>
#include <sstream>
bool contains(std::unordered_map<std::string, int> const &map, std::string const &key) {
return map.find(key) != map.end();
}
namespace argument_parser {
argument::argument()
: id(0), name(), action(std::make_unique<non_parametered_action>([]() {})), required(false), invoked(false) {}
argument::argument(const argument &other)
: id(other.id), name(other.name), action(other.action->clone()), required(other.required),
invoked(other.invoked), help_text(other.help_text) {}
argument &argument::operator=(const argument &other) {
if (this != &other) {
id = other.id;
name = other.name;
action = other.action->clone();
required = other.required;
invoked = other.invoked;
help_text = other.help_text;
}
return *this;
}
bool argument::is_required() const {
return required;
}
bool argument::is_invoked() const {
return invoked;
}
std::string argument::get_name() const {
return name;
}
std::string argument::get_help_text() const {
return help_text;
}
void argument::set_required(bool val) {
required = val;
}
void argument::set_invoked(bool val) {
invoked = val;
}
void argument::set_help_text(std::string const &text) {
help_text = text;
}
void base_parser::on_complete(std::function<void(base_parser const &)> const &handler) {
on_complete_events.emplace_back(handler);
}
std::string
base_parser::build_help_text(std::initializer_list<conventions::convention const *const> convention_types) const {
std::stringstream ss;
ss << "Usage: " << program_name << " [OPTIONS]...\n";
for (auto const &[id, arg] : argument_map) {
auto short_arg = reverse_short_arguments.at(id);
auto long_arg = reverse_long_arguments.at(id);
ss << "\t";
for (auto const &convention : convention_types) {
ss << convention->short_prec() << short_arg << ", " << convention->long_prec() << long_arg << "\t";
}
ss << arg.help_text << "\n";
}
return ss.str();
}
argument &base_parser::get_argument(conventions::parsed_argument const &arg) {
if (arg.first == conventions::argument_type::LONG) {
auto long_pos = long_arguments.find(arg.second);
if (long_pos != long_arguments.end())
return argument_map.at(long_pos->second);
} else if (arg.first == conventions::argument_type::SHORT) {
auto short_pos = short_arguments.find(arg.second);
if (short_pos != short_arguments.end())
return argument_map.at(short_pos->second);
} else if (arg.first == conventions::argument_type::INTERCHANGABLE) {
auto long_pos = long_arguments.find(arg.second);
if (long_pos != long_arguments.end())
return argument_map.at(long_pos->second);
auto short_pos = short_arguments.find(arg.second);
if (short_pos != short_arguments.end())
return argument_map.at(short_pos->second);
}
throw std::runtime_error("Unknown argument: " + arg.second);
}
void base_parser::handle_arguments(std::initializer_list<conventions::convention const *const> convention_types) {
for (auto it = parsed_arguments.begin(); it != parsed_arguments.end(); ++it) {
std::stringstream error_stream;
bool arg_correctly_handled = false;
for (auto const &convention_type : convention_types) {
auto extracted = convention_type->get_argument(*it);
if (extracted.first == conventions::argument_type::ERROR) {
error_stream << "Convention \"" << convention_type->name() << "\" failed with: " << extracted.second
<< "\n";
continue;
}
try {
argument &corresponding_argument = get_argument(extracted);
if (corresponding_argument.expects_parameter()) {
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
throw std::runtime_error("expected value for argument " + extracted.second);
}
auto value_raw =
convention_type->requires_next_token() ? *(++it) : convention_type->extract_value(*it);
corresponding_argument.action->invoke_with_parameter(value_raw);
} else {
corresponding_argument.action->invoke();
}
corresponding_argument.set_invoked(true);
arg_correctly_handled = true;
break; // Convention succeeded, move to the next argument token
} catch (const std::runtime_error &e) {
error_stream << "Convention \"" << convention_type->name() << "\" failed with: " << e.what()
<< "\n";
}
}
if (!arg_correctly_handled) {
throw std::runtime_error("All trials for argument: \n\t\"" + *it + "\"\n failed with: \n" +
error_stream.str());
}
}
check_for_required_arguments(convention_types);
fire_on_complete_events();
}
void base_parser::display_help(std::initializer_list<conventions::convention const *const> convention_types) const {
std::cout << build_help_text(convention_types);
}
std::optional<int> base_parser::find_argument_id(std::string const &arg) const {
auto long_pos = long_arguments.find(arg);
auto short_post = short_arguments.find(arg);
if (long_pos != long_arguments.end())
return long_pos->second;
if (short_post != short_arguments.end())
return short_post->second;
return std::nullopt;
}
void base_parser::assert_argument_not_exist(std::string const &short_arg, std::string const &long_arg) const {
if (contains(short_arguments, short_arg) || contains(long_arguments, long_arg)) {
throw std::runtime_error("The key already exists!");
}
}
void base_parser::set_argument_status(bool is_required, std::string const &help_text, argument &arg) {
arg.set_required(is_required);
arg.set_help_text(help_text);
}
void base_parser::place_argument(int id, argument const &arg, std::string const &short_arg,
std::string const &long_arg) {
argument_map[id] = arg;
short_arguments[short_arg] = id;
reverse_short_arguments[id] = short_arg;
long_arguments[long_arg] = id;
reverse_long_arguments[id] = long_arg;
}
void base_parser::check_for_required_arguments(
std::initializer_list<conventions::convention const *const> convention_types) {
std::vector<std::pair<std::string, std::string>> required_args;
for (auto const &[key, arg] : argument_map) {
if (arg.is_required() and not arg.is_invoked()) {
required_args.emplace_back<std::pair<std::string, std::string>>(
{reverse_short_arguments[key], reverse_long_arguments[key]});
}
}
if (not required_args.empty()) {
std::cerr << "These arguments were expected but not provided: ";
for (auto const &[s, l] : required_args) {
std::cerr << "[-" << s << ", --" << l << "] ";
}
std::cerr << "\n";
display_help(convention_types);
}
}
void base_parser::fire_on_complete_events() const {
for (auto const &event : on_complete_events) {
event(*this);
}
}
} // namespace argument_parser

View File

@@ -0,0 +1,31 @@
#ifdef __APPLE__
#include "macos_parser.hpp"
namespace argument_parser {
macos_parser::macos_parser() {
const int argc = *_NSGetArgc();
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
program_name = (argv[0]);
for (int i = 1; i < argc; ++i) {
if (argv[i] != nullptr)
parsed_arguments.emplace_back(argv[i]);
}
}
}
namespace v2 {
macos_parser::macos_parser() {
const int argc = *_NSGetArgc();
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
set_program_name(argv[0]);
for (int i = 1; i < argc; ++i) {
if (argv[i] != nullptr)
ref_parsed_args().emplace_back(argv[i]);
}
}
}
} // namespace v2
} // namespace argument_parser
#endif