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