From ad81df09abbfc3d9dd7240b9f58d996b2270e4a5 Mon Sep 17 00:00:00 2001 From: Gabriel Galli Date: Mon, 10 Feb 2025 00:45:58 -0300 Subject: [PATCH] feat: first working draft of getting values out of parsed command-line --- examples/main.cpp | 8 ++- include/experimental/parsing.hpp | 96 +++++++++++++++++++++++++------- 2 files changed, 82 insertions(+), 22 deletions(-) diff --git a/examples/main.cpp b/examples/main.cpp index be48e42..76805fa 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -14,7 +14,13 @@ int main(int argc, char const *argv[]) { .Flg<"disable-content-trust">({.help = "Skip image verification"}) .Flg<"quiet", "q">({.help = "Supress verbose output"}); - parse(p, std::span{argv, argc}); + auto const map = parse(p, std::span{argv, argc}); + std::print("\nargs map (size {}):\n", map.args.size()); + std::print("name: {}\n", map.get<"name">()); + std::print("platform: {}\n", map.get<"platform">()); + std::print("all-tags: {}\n", map.get<"all-tags">()); + std::print("disable-content-trust: {}\n", map.get<"disable-content-trust">()); + std::print("quiet: {}\n", map.get<"quiet">()); // p.SetValue<"age">(28); // auto age = p.GetValue<"name">(); diff --git a/include/experimental/parsing.hpp b/include/experimental/parsing.hpp index 7e3bb58..7eda3c8 100644 --- a/include/experimental/parsing.hpp +++ b/include/experimental/parsing.hpp @@ -1,6 +1,7 @@ #ifndef OPZIONI_PARSING_H #define OPZIONI_PARSING_H +#include #include #include #include @@ -42,28 +43,37 @@ constexpr ParsedOption try_parse_option(std::string_view const) noexcept; struct ArgsView { std::string_view exec_path{}; + // TODO: put positionals and options on the same map when we + // start querying the program args? std::vector positionals; std::map options; }; -struct ArgsMap { +template +struct ArgsMap; + +template +struct ArgsMap, TypeList> { + using arg_names = StringList; + using arg_types = TypeList; + std::string_view exec_path{}; std::map args; - std::any operator[](std::string_view name) const { - if (!args.contains(name)) throw opzioni::ArgumentNotFound(name); - return args.at(name); + template + typename GetType::type get() const { + using T = GetType::type; + static_assert(!std::is_same_v< T, void >, "unknown parameter name"); + auto const val = args.find(Name); + if (val == args.end()) throw opzioni::ArgumentNotFound(Name.data); + return std::any_cast(val->second); } - template - T as(std::string_view name) const { - auto const arg = (*this)[name]; - return std::any_cast(arg); - } + // TODO: get_or() bool has(std::string_view name) const noexcept { return args.contains(name); } - auto size() const noexcept { return this->args.size(); } + auto size() const noexcept { return args.size(); } }; template @@ -76,11 +86,11 @@ struct ArgParser, TypeList> { ArgParser(Program, TypeList> const &program) : program(program) {} - ArgsMap operator()(std::span args) { - ArgsMap map; - map.exec_path = args[0]; - return map; - } + // auto operator()(std::span args) { + // ArgsMap map; + // map.exec_path = args[0]; + // return map; + // } auto get_args_view(std::span args) { ArgsView view; @@ -124,27 +134,71 @@ struct ArgParser, TypeList> { return view; } - auto get_args_map() {} + auto get_args_map(ArgsView const &view) const { + auto map = ArgsMap, TypeList>{.exec_path = view.exec_path}; + std::size_t idx = sizeof...(ArgTypes) - 1; + std::size_t idx_pos = 0; + ((process(idx, map, view, idx_pos), idx--), ...); + return map; + } + + template + auto process(std::size_t idx, ArgsMap, TypeList> &map, ArgsView const &view, std::size_t &idx_pos) const { + using T = GetType, TypeList>::type; + auto const arg = program.args[idx]; + switch (arg.type) { + case ArgType::POS: { + std::print("process POS {}=={}, idx {}, idx_pos {}\n", ArgName.data, arg.name, idx, idx_pos); + if (idx_pos < view.positionals.size()) { + map.args[ArgName] = opzioni::convert(view.positionals[idx_pos]); + idx_pos += 1; + } else if (arg.is_required) { + // TODO + throw "missing positional"; + } + break; + } + case ArgType::OPT: { + std::print("process OPT {}=={}, idx {}\n", ArgName.data, arg.name, idx); + auto const opt = view.options.find(ArgName); + if (opt != view.options.end()) { + std::print("OPT {} found, value: {}\n", ArgName.data, opt->second); + map.args[ArgName] = opzioni::convert(opt->second); + } else if (arg.is_required) { + // TODO + throw "missing option"; + } + break; + } + case ArgType::FLG: { + std::print("process FLG {}=={}, idx {}\n", ArgName.data, arg.name, idx); + map.args[ArgName] = view.options.contains(ArgName); + break; + } + } + } }; template auto parse(Program, TypeList> const &program, std::span args) { auto parser = ArgParser, TypeList>(program); - auto const i = parser.get_args_view(args); - std::print("positionals ({}):", i.positionals.size()); - for (auto &&p : i.positionals) { + auto const view = parser.get_args_view(args); + std::print("positionals ({}):", view.positionals.size()); + for (auto &&p : view.positionals) { std::print(" {}", p); } std::print("\n"); std::print("options & flags:\n"); - for (auto &&o : i.options) { + for (auto &&o : view.options) { std::print("- {} = {}\n", o.first, o.second); } + auto const map = parser.get_args_map(view); + // auto map = parse_args(program, args); // check_contains_required(program, map); - return parser; + return map; } // +---------------------+