22 #ifndef GEARS_OPTPARSE_OPTION_PARSER_HPP 
   23 #define GEARS_OPTPARSE_OPTION_PARSER_HPP 
   26 #include "formatter.hpp" 
   42     std::vector<subcommand> subcommands;
 
   44     std::unique_ptr<formatter> format = utility::make_unique<formatter>();
 
   46     std::ptrdiff_t index = -1;
 
   48     bool is_option(
const std::string& arg) 
const noexcept {
 
   49         return arg.
size() >= 2 && arg.front() == 
'-';
 
   52     template<
typename ForwardIt>
 
   53     ForwardIt process_subcommand(ForwardIt 
begin, ForwardIt 
end) {
 
   58         std::string arg = *
begin;
 
   63         auto&& it = std::find_if(subcommands.begin(), subcommands.end(), [&arg](
const subcommand& sub) {
 
   64             return sub.name == arg;
 
   67         if(it != subcommands.end()) {
 
   68             index = std::distance(subcommands.begin(), it);
 
   69             active_options = &(it->options);
 
   77     template<
typename ForwardIt>
 
   78     ForwardIt parse_long_option(std::string key, ForwardIt begin, ForwardIt end) {
 
   80         auto&& pos = key.find(
'=');
 
   81         bool has_explicit_value = 
false;
 
   84         if(pos != std::string::npos) {
 
   85             value = key.substr(pos + 1);
 
   86             key = key.substr(0, pos);
 
   87             has_explicit_value = 
true;
 
   91         auto&& it = std::find_if(active_options->
begin(), active_options->
end(), [&key](
const option& opt) {
 
   92             return opt.is(key.substr(2));
 
   95         if(it == active_options->
end()) {
 
  100         size_t argc = std::distance(begin, end);
 
  104         if(!opt.takes_value() && has_explicit_value) {
 
  108         if(opt.takes_value() && !has_explicit_value) {
 
  110             if(argc - 1 < opt.nargs()) {
 
  115             for(
size_t i = 0; i < opt.nargs(); ++i) {
 
  117                 value.push_back(
'\n');
 
  121             if(!value.empty() && value.back() == 
'\n') {
 
  127         if(opt.ptr != 
nullptr) {
 
  128             opt.ptr->parse(key, value);
 
  134     template<
typename ForwardIt>
 
  135     ForwardIt parse_short_option(
const std::string& arg, ForwardIt begin, ForwardIt end) {
 
  138         for(
size_t j = 1 ; j < arg.size(); ++j) {
 
  140             bool has_explicit_value = 
false;
 
  141             std::string key = 
"-";
 
  145             if(j + 2 < arg.size() && arg[j + 1] == 
'=') {
 
  146                 value = arg.substr(j + 2);
 
  150                 has_explicit_value = 
true;
 
  153             auto&& it = std::find_if(active_options->
begin(), active_options->
end(), [&ch](
const option& opt) {
 
  157             if(it == active_options->
end()) {
 
  162             size_t argc = std::distance(begin, end);
 
  164             if(has_explicit_value && !opt.takes_value()) {
 
  169             if(opt.takes_value() && !has_explicit_value) {
 
  171                 if(j + 1 != arg.size()) {
 
  175                 if(argc - 1 < opt.nargs()) {
 
  179                 for(
size_t i = 0; i < opt.nargs(); ++i) {
 
  181                     value.push_back(
'\n');
 
  185                 if(!value.empty() && value.back() == 
'\n') {
 
  190             if(opt.ptr != 
nullptr) {
 
  191                 opt.ptr->parse(key, value);
 
  198     template<
typename It>
 
  199     arguments make_args(It begin, It end)
 const {
 
  201             return { *active_options, std::vector<std::string>(
begin, 
end), 
"" };
 
  203         auto&& sub = subcommands[index];
 
  204         return { *active_options, std::vector<std::string>(
begin, 
end), sub.name };
 
  225     option_parser(std::initializer_list<option> options): options(std::move(options)) {}
 
  236     template<
typename... Args>
 
  237     void add(Args&&... args) {
 
  238         options.
add(std::forward<Args>(args)...);
 
  249         subcommands.push_back(std::move(sub));
 
  260     template<
typename Formatter>
 
  262         static_assert(std::is_base_of<formatter, Formatter>::value, 
"Must derive from formatter");
 
  263         format = utility::make_unique<Formatter>(form);
 
  284     template<
typename ForwardIt>
 
  286         static_assert(std::is_constructible<std::string, decltype(*begin)>{},
 
  287                       "Iterator must return type convertible to std::string");
 
  290             return {*active_options, {}, 
""};
 
  294         if(program_name.empty()) {
 
  295             program_name = *begin++;
 
  302         begin = process_subcommand(begin, end);
 
  306             std::string arg = *
begin;
 
  310                 return make_args(++begin, end);
 
  317                     begin = parse_long_option(arg, begin, end);
 
  321                     begin = parse_short_option(arg, begin, end);
 
  331         return make_args(begin, end);
 
  348         for(
auto&& opt : *active_options) {
 
  349             if((opt.flags & trait::required) == trait::required && !opt.is_active()) {
 
  376     template<
typename ForwardIt>
 
  377     arguments parse(ForwardIt begin, ForwardIt end, std::ostream& out = std::cout, std::ostream& err = std::cerr) {
 
  381             if(args.options.is_active(
"help")) {
 
  383                 std::exit(EXIT_SUCCESS);
 
  393         catch(
const std::exception& e) {
 
  394             err << 
format_usage() << program_name << 
": error: " << e.what() << 
'\n';
 
  404         std::exit(EXIT_FAILURE);
 
  414         return format->description(index == -1 ? epilogue : subcommands[index].epilogue);
 
  424         return format->epilogue(index == -1 ? epilogue : subcommands[index].epilogue);
 
  434         return format->usage(program_name,
 
  435                              index == -1 ? 
"" : subcommands[index].name,
 
  436                              index == -1 ? usage : subcommands[index].usage);
 
  446         return format->subcommands(subcommands);
 
  457         return format->options(*active_options);
 
  482         if(active_options == &options) {
 
  485             if(!subcommands.empty()) {
 
  486                 result.push_back(
'\n');
 
  503     void error(
const std::string& message, std::ostream& err = std::cerr) {
 
  505         err << format->wrap(program_name + 
": error: " + message);
 
  506         std::exit(EXIT_FAILURE);
 
  512 #endif // GEARS_OPTPARSE_OPTION_PARSER_HPP