#include "programopts.h" #include #include using namespace std::string_literals; namespace { struct PrefixCmp { bool operator()(const std::string& lhs, const std::string& rhs) const { return !(lhs.starts_with(rhs) || rhs.starts_with(lhs)) && lhs < rhs; } }; } struct ProgramOpts::impl { int m_argc; char** m_argv; std::string m_programName; std::vector m_parameters; std::map, PrefixCmp> m_option_prefixes; }; ProgramOpts::ProgramOpts(int argc, char* argv[], std::map>& option_prefixes): m_pimpl(std::make_unique()) { m_pimpl->m_argc = argc; m_pimpl->m_argv = argv; if (m_pimpl->m_argc >= 1) m_pimpl->m_programName = m_pimpl->m_argv[0]; //std::copy(option_prefixes.begin(), option_prefixes.end(), std::inserter(m_pimpl->m_option_prefixes, std::next(m_pimpl->m_option_prefixes.begin()))); } ProgramOpts::~ProgramOpts() { } void ProgramOpts::process() { for (size_t i = 1; i < m_pimpl->m_argc; i++) { std::string arg{ m_pimpl->m_argv[i] }; if (arg.size() == 0) throw std::runtime_error("Empty option #"s + std::to_string(i)); if (arg[0] != '-') { // non-option parameter m_pimpl->m_parameters.push_back(arg); } else { auto prefix_iterator = m_pimpl->m_option_prefixes.find(arg); if (prefix_iterator == m_pimpl->m_option_prefixes.end()) throw std::runtime_error("Unknown option: "s + arg); auto& [prefix, f] = *prefix_iterator; std::string optional_parameter; bool parameter_provided{ false }; if (prefix.size() < arg.size()) { optional_parameter = arg.substr(prefix.size()); } else { if (i < m_pimpl->m_argc - 1) optional_parameter = m_pimpl->m_argv[i + 1]; if (optional_parameter.size() > 0 && optional_parameter[0] == '-') optional_parameter = ""; else parameter_provided = true; } bool parameter_consumed = f(optional_parameter); // call the function from the map if (parameter_provided && parameter_consumed) i++; // skip parameter } } } std::string ProgramOpts::programName() { return m_pimpl->m_programName; } std::vector ProgramOpts::nonOptionArguments() { return m_pimpl->m_parameters; }