summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/cli/argparse.h
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/cli/argparse.h')
-rw-r--r--comm/third_party/botan/src/cli/argparse.h280
1 files changed, 280 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/cli/argparse.h b/comm/third_party/botan/src/cli/argparse.h
new file mode 100644
index 0000000000..4df4a10c83
--- /dev/null
+++ b/comm/third_party/botan/src/cli/argparse.h
@@ -0,0 +1,280 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_CLI_ARGPARSE_H_
+#define BOTAN_CLI_ARGPARSE_H_
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <botan/parsing.h>
+#include "cli_exceptions.h"
+
+namespace Botan_CLI {
+
+class Argument_Parser final
+ {
+ public:
+ Argument_Parser(const std::string& spec,
+ const std::vector<std::string>& extra_flags = {},
+ const std::vector<std::string>& extra_opts = {});
+
+ void parse_args(const std::vector<std::string>& params);
+
+ bool flag_set(const std::string& flag) const;
+
+ bool has_arg(const std::string& opt_name) const;
+ std::string get_arg(const std::string& option) const;
+
+ std::string get_arg_or(const std::string& option, const std::string& otherwise) const;
+
+ size_t get_arg_sz(const std::string& option) const;
+
+ std::vector<std::string> get_arg_list(const std::string& what) const;
+
+ private:
+ // set in constructor
+ std::vector<std::string> m_spec_args;
+ std::set<std::string> m_spec_flags;
+ std::map<std::string, std::string> m_spec_opts;
+ std::string m_spec_rest;
+
+ // set in parse_args()
+ std::map<std::string, std::string> m_user_args;
+ std::set<std::string> m_user_flags;
+ std::vector<std::string> m_user_rest;
+ };
+
+bool Argument_Parser::flag_set(const std::string& flag_name) const
+ {
+ return m_user_flags.count(flag_name) > 0;
+ }
+
+bool Argument_Parser::has_arg(const std::string& opt_name) const
+ {
+ return m_user_args.count(opt_name) > 0;
+ }
+
+std::string Argument_Parser::get_arg(const std::string& opt_name) const
+ {
+ auto i = m_user_args.find(opt_name);
+ if(i == m_user_args.end())
+ {
+ // this shouldn't occur unless you passed the wrong thing to get_arg
+ throw CLI_Error("Unknown option " + opt_name + " used (program bug)");
+ }
+ return i->second;
+ }
+
+std::string Argument_Parser::get_arg_or(const std::string& opt_name, const std::string& otherwise) const
+ {
+ auto i = m_user_args.find(opt_name);
+ if(i == m_user_args.end() || i->second.empty())
+ {
+ return otherwise;
+ }
+ return i->second;
+ }
+
+size_t Argument_Parser::get_arg_sz(const std::string& opt_name) const
+ {
+ const std::string s = get_arg(opt_name);
+
+ try
+ {
+ return static_cast<size_t>(std::stoul(s));
+ }
+ catch(std::exception&)
+ {
+ throw CLI_Usage_Error("Invalid integer value '" + s + "' for option " + opt_name);
+ }
+ }
+
+std::vector<std::string> Argument_Parser::get_arg_list(const std::string& what) const
+ {
+ if(what == m_spec_rest)
+ return m_user_rest;
+
+ return Botan::split_on(get_arg(what), ',');
+ }
+
+void Argument_Parser::parse_args(const std::vector<std::string>& params)
+ {
+ std::vector<std::string> args;
+ for(auto const& param : params)
+ {
+ if(param.find("--") == 0)
+ {
+ // option
+ const auto eq = param.find('=');
+
+ if(eq == std::string::npos)
+ {
+ const std::string opt_name = param.substr(2, std::string::npos);
+
+ if(m_spec_flags.count(opt_name) == 0)
+ {
+ if(m_spec_opts.count(opt_name))
+ {
+ throw CLI_Usage_Error("Invalid usage of option --" + opt_name +
+ " without value");
+ }
+ else
+ {
+ throw CLI_Usage_Error("Unknown flag --" + opt_name);
+ }
+ }
+ m_user_flags.insert(opt_name);
+ }
+ else
+ {
+ const std::string opt_name = param.substr(2, eq - 2);
+ const std::string opt_val = param.substr(eq + 1, std::string::npos);
+
+ if(m_spec_opts.count(opt_name) == 0)
+ {
+ throw CLI_Usage_Error("Unknown option --" + opt_name);
+ }
+
+ m_user_args.insert(std::make_pair(opt_name, opt_val));
+ }
+ }
+ else
+ {
+ // argument
+ args.push_back(param);
+ }
+ }
+
+ if(flag_set("help"))
+ return;
+
+ if(args.size() < m_spec_args.size())
+ {
+ // not enough arguments
+ throw CLI_Usage_Error("Invalid argument count, got " +
+ std::to_string(args.size()) +
+ " expected " +
+ std::to_string(m_spec_args.size()));
+ }
+
+ bool seen_stdin_flag = false;
+ size_t arg_i = 0;
+ for(auto const& arg : m_spec_args)
+ {
+ m_user_args.insert(std::make_pair(arg, args[arg_i]));
+
+ if(args[arg_i] == "-")
+ {
+ if(seen_stdin_flag)
+ {
+ throw CLI_Usage_Error("Cannot specify '-' (stdin) more than once");
+ }
+ seen_stdin_flag = true;
+ }
+
+ ++arg_i;
+ }
+
+ if(m_spec_rest.empty())
+ {
+ if(arg_i != args.size())
+ {
+ throw CLI_Usage_Error("Too many arguments");
+ }
+ }
+ else
+ {
+ m_user_rest.assign(args.begin() + arg_i, args.end());
+ }
+
+ // Now insert any defaults for options not supplied by the user
+ for(auto const& opt : m_spec_opts)
+ {
+ if(m_user_args.count(opt.first) == 0)
+ {
+ m_user_args.insert(opt);
+ }
+ }
+ }
+
+Argument_Parser::Argument_Parser(const std::string& spec,
+ const std::vector<std::string>& extra_flags,
+ const std::vector<std::string>& extra_opts)
+ {
+ class CLI_Error_Invalid_Spec final : public CLI_Error
+ {
+ public:
+ explicit CLI_Error_Invalid_Spec(const std::string& bad_spec)
+ : CLI_Error("Invalid command spec '" + bad_spec + "'") {}
+ };
+
+ const std::vector<std::string> parts = Botan::split_on(spec, ' ');
+
+ if(parts.size() == 0)
+ {
+ throw CLI_Error_Invalid_Spec(spec);
+ }
+
+ for(size_t i = 1; i != parts.size(); ++i)
+ {
+ const std::string s = parts[i];
+
+ if(s.empty()) // ?!? (shouldn't happen)
+ {
+ throw CLI_Error_Invalid_Spec(spec);
+ }
+
+ if(s.size() > 2 && s[0] == '-' && s[1] == '-')
+ {
+ // option or flag
+
+ auto eq = s.find('=');
+
+ if(eq == std::string::npos)
+ {
+ m_spec_flags.insert(s.substr(2, std::string::npos));
+ }
+ else
+ {
+ m_spec_opts.insert(std::make_pair(s.substr(2, eq - 2), s.substr(eq + 1, std::string::npos)));
+ }
+ }
+ else if(s[0] == '*')
+ {
+ // rest argument
+ if(m_spec_rest.empty() && s.size() > 2)
+ {
+ m_spec_rest = s.substr(1, std::string::npos);
+ }
+ else
+ {
+ throw CLI_Error_Invalid_Spec(spec);
+ }
+ }
+ else
+ {
+ // named argument
+ if(!m_spec_rest.empty()) // rest arg wasn't last
+ {
+ throw CLI_Error_Invalid_Spec(spec);
+ }
+
+ m_spec_args.push_back(s);
+ }
+ }
+
+ for(std::string flag : extra_flags)
+ m_spec_flags.insert(flag);
+ for(std::string opt : extra_opts)
+ m_spec_opts.insert(std::make_pair(opt, ""));
+ }
+
+
+}
+
+#endif