Fleet  0.0.9
Inference in the LOT
CL11.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 // Distributed under the 3-Clause BSD License. See accompanying
4 // file LICENSE or https://github.com/CLIUtils/CLI11 for details.
5 
6 // This file was generated using MakeSingleHeader.py in CLI11/scripts
7 // from: v1.4.0
8 
9 // This has the complete CLI library in one file.
10 
11 #include <sys/stat.h>
12 #include <deque>
13 #include <set>
14 #include <iostream>
15 #include <string>
16 #include <iterator>
17 #include <tuple>
18 #include <locale>
19 #include <functional>
20 #include <numeric>
21 #include <iomanip>
22 #include <sys/types.h>
23 #include <utility>
24 #include <exception>
25 #include <algorithm>
26 #include <fstream>
27 #include <sstream>
28 #include <stdexcept>
29 #include <vector>
30 #include <type_traits>
31 #include <memory>
32 
33 // From CLI/Version.hpp
34 
35 namespace CLI {
36 
37 // Note that all code in CLI11 must be in a namespace, even if it just a define.
38 
39 #define CLI11_VERSION_MAJOR 1
40 #define CLI11_VERSION_MINOR 4
41 #define CLI11_VERSION_PATCH 0
42 #define CLI11_VERSION "1.4.0"
43 
44 } // namespace CLI
45 
46 // From CLI/StringTools.hpp
47 
48 namespace CLI {
49 namespace detail {
50 
51 // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
53 inline std::vector<std::string> split(const std::string &s, char delim) {
54  std::vector<std::string> elems;
55  // Check to see if empty string, give consistent result
56  if(s.empty())
57  elems.emplace_back("");
58  else {
59  std::stringstream ss;
60  ss.str(s);
61  std::string item;
62  while(std::getline(ss, item, delim)) {
63  elems.push_back(item);
64  }
65  }
66  return elems;
67 }
68 
70 template <typename T> std::string join(const T &v, std::string delim = ",") {
71  std::ostringstream s;
72  size_t start = 0;
73  for(const auto &i : v) {
74  if(start++ > 0)
75  s << delim;
76  s << i;
77  }
78  return s.str();
79 }
80 
82 template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
83  std::ostringstream s;
84  for(size_t start = 0; start < v.size(); start++) {
85  if(start > 0)
86  s << delim;
87  s << v[v.size() - start - 1];
88  }
89  return s.str();
90 }
91 
92 // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
93 
95 inline std::string &ltrim(std::string &str) {
96  auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
97  str.erase(str.begin(), it);
98  return str;
99 }
100 
102 inline std::string &ltrim(std::string &str, const std::string &filter) {
103  auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
104  str.erase(str.begin(), it);
105  return str;
106 }
107 
109 inline std::string &rtrim(std::string &str) {
110  auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
111  str.erase(it.base(), str.end());
112  return str;
113 }
114 
116 inline std::string &rtrim(std::string &str, const std::string &filter) {
117  auto it =
118  std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
119  str.erase(it.base(), str.end());
120  return str;
121 }
122 
124 inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
125 
127 inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); }
128 
130 inline std::string trim_copy(const std::string &str) {
131  std::string s = str;
132  return trim(s);
133 }
134 
136 inline std::string trim_copy(const std::string &str, const std::string &filter) {
137  std::string s = str;
138  return trim(s, filter);
139 }
141 inline void format_help(std::stringstream &out, std::string name, std::string description, size_t wid) {
142  name = " " + name;
143  out << std::setw(static_cast<int>(wid)) << std::left << name;
144  if(!description.empty()) {
145  if(name.length() >= wid)
146  out << std::endl << std::setw(static_cast<int>(wid)) << "";
147  out << description;
148  }
149  out << std::endl;
150 }
151 
153 template <typename T> bool valid_first_char(T c) { return std::isalpha(c, std::locale()) || c == '_'; }
154 
156 template <typename T> bool valid_later_char(T c) {
157  return std::isalnum(c, std::locale()) || c == '_' || c == '.' || c == '-';
158 }
159 
161 inline bool valid_name_string(const std::string &str) {
162  if(str.empty() || !valid_first_char(str[0]))
163  return false;
164  for(auto c : str.substr(1))
165  if(!valid_later_char(c))
166  return false;
167  return true;
168 }
169 
171 inline std::string to_lower(std::string str) {
172  std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) {
173  return std::tolower(x, std::locale());
174  });
175  return str;
176 }
177 
179 inline std::vector<std::string> split_up(std::string str) {
180 
181  std::vector<char> delims = {'\'', '\"'};
182  auto find_ws = [](char ch) { return std::isspace<char>(ch, std::locale()); };
183  trim(str);
184 
185  std::vector<std::string> output;
186 
187  while(!str.empty()) {
188  if(str[0] == '\'') {
189  auto end = str.find('\'', 1);
190  if(end != std::string::npos) {
191  output.push_back(str.substr(1, end - 1));
192  str = str.substr(end + 1);
193  } else {
194  output.push_back(str.substr(1));
195  str = "";
196  }
197  } else if(str[0] == '\"') {
198  auto end = str.find('\"', 1);
199  if(end != std::string::npos) {
200  output.push_back(str.substr(1, end - 1));
201  str = str.substr(end + 1);
202  } else {
203  output.push_back(str.substr(1));
204  str = "";
205  }
206 
207  } else {
208  auto it = std::find_if(std::begin(str), std::end(str), find_ws);
209  if(it != std::end(str)) {
210  std::string value = std::string(str.begin(), it);
211  output.push_back(value);
212  str = std::string(it, str.end());
213  } else {
214  output.push_back(str);
215  str = "";
216  }
217  }
218  trim(str);
219  }
220 
221  return output;
222 }
223 
228 inline std::string fix_newlines(std::string leader, std::string input) {
229  std::string::size_type n = 0;
230  while(n != std::string::npos && n < input.size()) {
231  n = input.find('\n', n);
232  if(n != std::string::npos) {
233  input = input.substr(0, n + 1) + leader + input.substr(n + 1);
234  n += leader.size();
235  }
236  }
237  return input;
238 }
239 
240 } // namespace detail
241 } // namespace CLI
242 
243 // From CLI/Error.hpp
244 
245 namespace CLI {
246 
247 // Use one of these on all error classes
248 #define CLI11_ERROR_DEF(parent, name) \
249  protected: \
250  name(std::string name, std::string msg, int exit_code) : parent(std::move(name), std::move(msg), exit_code) {} \
251  name(std::string name, std::string msg, ExitCodes exit_code) \
252  : parent(std::move(name), std::move(msg), exit_code) {} \
253  \
254  public: \
255  name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
256  name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
257 
258 // This is added after the one above if a class is used directly and builds its own message
259 #define CLI11_ERROR_SIMPLE(name) \
260  name(std::string msg) : name(#name, msg, ExitCodes::name) {}
261 
264 enum class ExitCodes {
265  Success = 0,
266  IncorrectConstruction = 100,
269  FileError,
275  ExtrasError,
276  INIError,
277  InvalidError,
281  BaseClass = 127
282 };
283 
284 // Error definitions
285 
291 
293 class Error : public std::runtime_error {
294  int exit_code;
295  std::string name{"Error"};
296 
297  public:
298  int get_exit_code() const { return exit_code; }
299 
300  std::string get_name() const { return name; }
301 
302  Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
303  : runtime_error(msg), exit_code(exit_code), name(std::move(name)) {}
304 
305  Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
306 };
307 
308 // Note: Using Error::Error constructors does not work on GCC 4.7
309 
311 class ConstructionError : public Error {
313 };
314 
319  static IncorrectConstruction PositionalFlag(std::string name) {
320  return IncorrectConstruction(name + ": Flags cannot be positional");
321  }
322  static IncorrectConstruction Set0Opt(std::string name) {
323  return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
324  }
325  static IncorrectConstruction ChangeNotVector(std::string name) {
326  return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
327  }
328  static IncorrectConstruction AfterMultiOpt(std::string name) {
329  return IncorrectConstruction(
330  name + ": You can't change expected arguments after you've changed the multi option policy!");
331  }
332  static IncorrectConstruction MissingOption(std::string name) {
333  return IncorrectConstruction("Option " + name + " is not defined");
334  }
335  static IncorrectConstruction MultiOptionPolicy(std::string name) {
336  return IncorrectConstruction(name + ": multi_option_policy only works for flags and single value options");
337  }
338 };
339 
344  static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); }
345  static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
346  static BadNameString DashesOnly(std::string name) {
347  return BadNameString("Must have a name, not just dashes: " + name);
348  }
349  static BadNameString MultiPositionalNames(std::string name) {
350  return BadNameString("Only one positional name allowed, remove: " + name);
351  }
352 };
353 
357  OptionAlreadyAdded(std::string name)
358  : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {}
359  static OptionAlreadyAdded Requires(std::string name, std::string other) {
360  return OptionAlreadyAdded(name + " requires " + other, ExitCodes::OptionAlreadyAdded);
361  }
362  static OptionAlreadyAdded Excludes(std::string name, std::string other) {
363  return OptionAlreadyAdded(name + " excludes " + other, ExitCodes::OptionAlreadyAdded);
364  }
365 };
366 
367 // Parsing errors
368 
370 class ParseError : public Error {
372 };
373 
374 // Not really "errors"
375 
377 class Success : public ParseError {
379  Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
380 };
381 
383 class CallForHelp : public ParseError {
385  CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
386 };
387 
389 class RuntimeError : public ParseError {
391  RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
392 };
393 
395 class FileError : public ParseError {
398  static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); }
399 };
400 
402 class ConversionError : public ParseError {
405  ConversionError(std::string member, std::string name)
406  : ConversionError("The value " + member + " is not an allowed value for " + name) {}
407  ConversionError(std::string name, std::vector<std::string> results)
408  : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
409  static ConversionError TooManyInputsFlag(std::string name) {
410  return ConversionError(name + ": too many inputs for a flag");
411  }
412  static ConversionError TrueFalse(std::string name) {
413  return ConversionError(name + ": Should be true/false or a number");
414  }
415 };
416 
418 class ValidationError : public ParseError {
421  ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {}
422 };
423 
425 class RequiredError : public ParseError {
427  RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
428  static RequiredError Subcommand(size_t min_subcom) {
429  if(min_subcom == 1)
430  return RequiredError("A subcommand");
431  else
432  return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands",
434  }
435 };
436 
438 class ArgumentMismatch : public ParseError {
441  ArgumentMismatch(std::string name, int expected, size_t recieved)
442  : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
443  ", got " + std::to_string(recieved))
444  : ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
445  ", got " + std::to_string(recieved)),
447 
448  static ArgumentMismatch AtLeast(std::string name, int num) {
449  return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required");
450  }
451  static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) {
452  return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");
453  }
454 };
455 
457 class RequiresError : public ParseError {
459  RequiresError(std::string curname, std::string subname)
460  : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
461 };
462 
464 class ExcludesError : public ParseError {
466  ExcludesError(std::string curname, std::string subname)
467  : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
468 };
469 
471 class ExtrasError : public ParseError {
473  ExtrasError(std::vector<std::string> args)
474  : ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
475  : "The following argument was not expected: ") +
476  detail::rjoin(args, " "),
478 };
479 
481 class INIError : public ParseError {
484  static INIError Extras(std::string item) { return INIError("INI was not able to parse " + item); }
485  static INIError NotConfigurable(std::string item) {
486  return INIError(item + ": This option is not allowed in a configuration file");
487  }
488 };
489 
491 class InvalidError : public ParseError {
493  InvalidError(std::string name)
494  : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
495  }
496 };
497 
500 class HorribleError : public ParseError {
503 };
504 
505 // After parsing
506 
508 class OptionNotFound : public Error {
510  OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {}
511 };
512 
514 
515 } // namespace CLI
516 
517 // From CLI/TypeTools.hpp
518 
519 namespace CLI {
520 
521 // Type tools
522 
523 // We could check to see if C++14 is being used, but it does not hurt to redefine this
524 // (even Google does this: https://github.com/google/skia/blob/master/include/private/SkTLogic.h)
525 // It is not in the std namespace anyway, so no harm done.
526 
527 template <bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
528 
529 template <typename T> struct is_vector { static const bool value = false; };
530 
531 template <class T, class A> struct is_vector<std::vector<T, A>> { static bool const value = true; };
532 
533 template <typename T> struct is_bool { static const bool value = false; };
534 
535 template <> struct is_bool<bool> { static bool const value = true; };
536 
537 namespace detail {
538 // Based generally on https://rmf.io/cxx11/almost-static-if
540 enum class enabler {};
541 
543 constexpr enabler dummy = {};
544 
545 // Type name print
546 
550 
551 template <typename T,
553 constexpr const char *type_name() {
554  return "INT";
555 }
556 
557 template <typename T,
558  enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
559 constexpr const char *type_name() {
560  return "UINT";
561 }
562 
563 template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> = detail::dummy>
564 constexpr const char *type_name() {
565  return "FLOAT";
566 }
567 
569 template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> = detail::dummy>
570 constexpr const char *type_name() {
571  return "VECTOR";
572 }
573 
574 template <typename T,
575  enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !is_vector<T>::value,
576  detail::enabler> = detail::dummy>
577 constexpr const char *type_name() {
578  return "TEXT";
579 }
580 
581 // Lexical cast
582 
584 template <typename T,
585  enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value) || std::is_enum<T>::value,
586  detail::enabler> = detail::dummy>
587 bool lexical_cast(std::string input, T &output) {
588  try {
589  size_t n = 0;
590  long long output_ll = std::stoll(input, &n, 0);
591  output = static_cast<T>(output_ll);
592  return n == input.size() && static_cast<long long>(output) == output_ll;
593  } catch(const std::invalid_argument &) {
594  return false;
595  } catch(const std::out_of_range &) {
596  return false;
597  }
598 }
599 
601 template <typename T,
602  enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
603 bool lexical_cast(std::string input, T &output) {
604  if(!input.empty() && input.front() == '-')
605  return false; // std::stoull happily converts negative values to junk without any errors.
606 
607  try {
608  size_t n = 0;
609  unsigned long long output_ll = std::stoull(input, &n, 0);
610  output = static_cast<T>(output_ll);
611  return n == input.size() && static_cast<unsigned long long>(output) == output_ll;
612  } catch(const std::invalid_argument &) {
613  return false;
614  } catch(const std::out_of_range &) {
615  return false;
616  }
617 }
618 
620 template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> = detail::dummy>
621 bool lexical_cast(std::string input, T &output) {
622  try {
623  size_t n = 0;
624  output = static_cast<T>(std::stold(input, &n));
625  return n == input.size();
626  } catch(const std::invalid_argument &) {
627  return false;
628  } catch(const std::out_of_range &) {
629  return false;
630  }
631 }
632 
634 template <typename T,
635  enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value &&
636  std::is_assignable<T &, std::string>::value,
637  detail::enabler> = detail::dummy>
638 bool lexical_cast(std::string input, T &output) {
639  output = input;
640  return true;
641 }
642 
644 template <typename T,
645  enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value &&
646  !std::is_assignable<T &, std::string>::value,
647  detail::enabler> = detail::dummy>
648 bool lexical_cast(std::string input, T &output) {
649 
650 // On GCC 4.7, thread_local is not available, so this optimization
651 // is turned off (avoiding multiple initialisations on multiple usages
652 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && __GNUC__ == 4 && (__GNUC_MINOR__ < 8)
653  std::istringstream is;
654 #else
655  static thread_local std::istringstream is;
656 #endif
657 
658  is.str(input);
659  is >> output;
660  return !is.fail() && !is.rdbuf()->in_avail();
661 }
662 
663 } // namespace detail
664 } // namespace CLI
665 
666 // From CLI/Split.hpp
667 
668 namespace CLI {
669 namespace detail {
670 
671 // Returns false if not a short option. Otherwise, sets opt name and rest and returns true
672 inline bool split_short(const std::string &current, std::string &name, std::string &rest) {
673  if(current.size() > 1 && current[0] == '-' && valid_first_char(current[1])) {
674  name = current.substr(1, 1);
675  rest = current.substr(2);
676  return true;
677  } else
678  return false;
679 }
680 
681 // Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true
682 inline bool split_long(const std::string &current, std::string &name, std::string &value) {
683  if(current.size() > 2 && current.substr(0, 2) == "--" && valid_first_char(current[2])) {
684  auto loc = current.find("=");
685  if(loc != std::string::npos) {
686  name = current.substr(2, loc - 2);
687  value = current.substr(loc + 1);
688  } else {
689  name = current.substr(2);
690  value = "";
691  }
692  return true;
693  } else
694  return false;
695 }
696 
697 // Splits a string into multiple long and short names
698 inline std::vector<std::string> split_names(std::string current) {
699  std::vector<std::string> output;
700  size_t val;
701  while((val = current.find(",")) != std::string::npos) {
702  output.push_back(trim_copy(current.substr(0, val)));
703  current = current.substr(val + 1);
704  }
705  output.push_back(trim_copy(current));
706  return output;
707 }
708 
710 inline std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
711 get_names(const std::vector<std::string> &input) {
712 
713  std::vector<std::string> short_names;
714  std::vector<std::string> long_names;
715  std::string pos_name;
716 
717  for(std::string name : input) {
718  if(name.length() == 0)
719  continue;
720  else if(name.length() > 1 && name[0] == '-' && name[1] != '-') {
721  if(name.length() == 2 && valid_first_char(name[1]))
722  short_names.emplace_back(1, name[1]);
723  else
724  throw BadNameString::OneCharName(name);
725  } else if(name.length() > 2 && name.substr(0, 2) == "--") {
726  name = name.substr(2);
727  if(valid_name_string(name))
728  long_names.push_back(name);
729  else
730  throw BadNameString::BadLongName(name);
731  } else if(name == "-" || name == "--") {
732  throw BadNameString::DashesOnly(name);
733  } else {
734  if(pos_name.length() > 0)
735  throw BadNameString::MultiPositionalNames(name);
736  pos_name = name;
737  }
738  }
739 
740  return std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>(
741  short_names, long_names, pos_name);
742 }
743 
744 } // namespace detail
745 } // namespace CLI
746 
747 // From CLI/Ini.hpp
748 
749 namespace CLI {
750 namespace detail {
751 
752 inline std::string inijoin(std::vector<std::string> args) {
753  std::ostringstream s;
754  size_t start = 0;
755  for(const auto &arg : args) {
756  if(start++ > 0)
757  s << " ";
758 
759  auto it = std::find_if(arg.begin(), arg.end(), [](char ch) { return std::isspace<char>(ch, std::locale()); });
760  if(it == arg.end())
761  s << arg;
762  else if(arg.find(R"(")") == std::string::npos)
763  s << R"(")" << arg << R"(")";
764  else
765  s << R"(')" << arg << R"(')";
766  }
767 
768  return s.str();
769 }
770 
771 struct ini_ret_t {
773  std::string fullname;
774 
776  std::vector<std::string> inputs;
777 
779  size_t level = 0;
780 
785  std::string parent() const {
786  std::vector<std::string> plist = detail::split(fullname, '.');
787  if(plist.size() > (level + 1))
788  return plist[level];
789  else
790  return "";
791  }
792 
794  std::string name() const {
795  std::vector<std::string> plist = detail::split(fullname, '.');
796  return plist.at(plist.size() - 1);
797  }
798 };
799 
801 inline std::vector<ini_ret_t> parse_ini(std::istream &input) {
802  std::string name, line;
803  std::string section = "default";
804 
805  std::vector<ini_ret_t> output;
806 
807  while(getline(input, line)) {
808  std::vector<std::string> items;
809 
810  detail::trim(line);
811  size_t len = line.length();
812  if(len > 1 && line[0] == '[' && line[len - 1] == ']') {
813  section = line.substr(1, len - 2);
814  } else if(len > 0 && line[0] != ';') {
815  output.emplace_back();
816  ini_ret_t &out = output.back();
817 
818  // Find = in string, split and recombine
819  auto pos = line.find("=");
820  if(pos != std::string::npos) {
821  name = detail::trim_copy(line.substr(0, pos));
822  std::string item = detail::trim_copy(line.substr(pos + 1));
823  items = detail::split_up(item);
824  } else {
825  name = detail::trim_copy(line);
826  items = {"ON"};
827  }
828 
829  if(detail::to_lower(section) == "default")
830  out.fullname = name;
831  else
832  out.fullname = section + "." + name;
833 
834  out.inputs.insert(std::end(out.inputs), std::begin(items), std::end(items));
835  }
836  }
837  return output;
838 }
839 
841 inline std::vector<ini_ret_t> parse_ini(const std::string &name) {
842 
843  std::ifstream input{name};
844  if(!input.good())
845  throw FileError::Missing(name);
846 
847  return parse_ini(input);
848 }
849 
850 } // namespace detail
851 } // namespace CLI
852 
853 // From CLI/Validators.hpp
854 
855 namespace CLI {
856 
863 
865 inline std::string ExistingFile(const std::string &filename) {
866  struct stat buffer;
867  bool exist = stat(filename.c_str(), &buffer) == 0;
868  bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
869  if(!exist) {
870  return "File does not exist: " + filename;
871  } else if(is_dir) {
872  return "File is actually a directory: " + filename;
873  }
874  return std::string();
875 }
876 
878 inline std::string ExistingDirectory(const std::string &filename) {
879  struct stat buffer;
880  bool exist = stat(filename.c_str(), &buffer) == 0;
881  bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
882  if(!exist) {
883  return "Directory does not exist: " + filename;
884  } else if(!is_dir) {
885  return "Directory is actually a file: " + filename;
886  }
887  return std::string();
888 }
889 
891 inline std::string ExistingPath(const std::string &filename) {
892  struct stat buffer;
893  bool const exist = stat(filename.c_str(), &buffer) == 0;
894  if(!exist) {
895  return "Path does not exist: " + filename;
896  }
897  return std::string();
898 }
899 
901 inline std::string NonexistentPath(const std::string &filename) {
902  struct stat buffer;
903  bool exist = stat(filename.c_str(), &buffer) == 0;
904  if(exist) {
905  return "Path already exists: " + filename;
906  }
907  return std::string();
908 }
909 
911 template <typename T> std::function<std::string(const std::string &)> Range(T min, T max) {
912  return [min, max](std::string input) {
913  T val;
914  detail::lexical_cast(input, val);
915  if(val < min || val > max)
916  return "Value " + input + " not in range " + std::to_string(min) + " to " + std::to_string(max);
917 
918  return std::string();
919  };
920 }
921 
923 template <typename T> std::function<std::string(const std::string &)> Range(T max) {
924  return Range(static_cast<T>(0), max);
925 }
926 
928 
929 } // namespace CLI
930 
931 // From CLI/Option.hpp
932 
933 namespace CLI {
934 
935 using results_t = std::vector<std::string>;
936 using callback_t = std::function<bool(results_t)>;
937 
938 class Option;
939 class App;
940 
941 using Option_p = std::unique_ptr<Option>;
942 
943 enum class MultiOptionPolicy { Throw, TakeLast, TakeFirst, Join };
944 
945 template <typename CRTP> class OptionBase {
946  friend App;
947 
948  protected:
950  std::string group_{"Options"};
951 
953  bool required_{false};
954 
956  bool ignore_case_{false};
957 
959  bool configurable_{true};
960 
962  MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
963 
964  template <typename T> void copy_to(T *other) const {
965  other->group(group_);
966  other->required(required_);
967  other->ignore_case(ignore_case_);
968  other->configurable(configurable_);
969  other->multi_option_policy(multi_option_policy_);
970  }
971 
972  public:
973  // setters
974 
976  CRTP *group(std::string name) {
977  group_ = name;
978  return static_cast<CRTP *>(this);
979  ;
980  }
981 
983  CRTP *required(bool value = true) {
984  required_ = value;
985  return static_cast<CRTP *>(this);
986  }
987 
989  CRTP *mandatory(bool value = true) { return required(value); }
990 
991  // Getters
992 
994  const std::string &get_group() const { return group_; }
995 
997  bool get_required() const { return required_; }
998 
1000  bool get_ignore_case() const { return ignore_case_; }
1001 
1003  bool get_configurable() const { return configurable_; }
1004 
1006  MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
1007 
1008  // Shortcuts for multi option policy
1009 
1011  CRTP *take_last() {
1012  CRTP *self = static_cast<CRTP *>(this);
1013  self->multi_option_policy(MultiOptionPolicy::TakeLast);
1014  return self;
1015  }
1016 
1018  CRTP *take_first() {
1019  CRTP *self = static_cast<CRTP *>(this);
1020  self->multi_option_policy(MultiOptionPolicy::TakeFirst);
1021  return self;
1022  }
1023 
1025  CRTP *join() {
1026  CRTP *self = static_cast<CRTP *>(this);
1027  self->multi_option_policy(MultiOptionPolicy::Join);
1028  return self;
1029  }
1030 
1032  CRTP *configurable(bool value = true) {
1033  configurable_ = value;
1034  return static_cast<CRTP *>(this);
1035  }
1036 };
1037 
1038 class OptionDefaults : public OptionBase<OptionDefaults> {
1039  public:
1040  OptionDefaults() = default;
1041 
1042  // Methods here need a different implementation if they are Option vs. OptionDefault
1043 
1045  OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
1046  multi_option_policy_ = value;
1047  return this;
1048  }
1049 
1051  OptionDefaults *ignore_case(bool value = true) {
1052  ignore_case_ = value;
1053  return this;
1054  }
1055 };
1056 
1057 class Option : public OptionBase<Option> {
1058  friend App;
1059 
1060  protected:
1063 
1065  std::vector<std::string> snames_;
1066 
1068  std::vector<std::string> lnames_;
1069 
1071  std::string pname_;
1072 
1074  std::string envname_;
1075 
1079 
1081  std::string description_;
1082 
1084  std::string defaultval_;
1085 
1087  std::string typeval_;
1088 
1090  bool default_{false};
1091 
1095 
1097  int expected_{1};
1098 
1100  bool changeable_{false};
1101 
1103  std::vector<std::function<std::string(std::string &)>> validators_;
1104 
1106  std::set<Option *> requires_;
1107 
1109  std::set<Option *> excludes_;
1110 
1114 
1116  App *parent_;
1117 
1119  callback_t callback_;
1120 
1124 
1126  results_t results_;
1127 
1129  bool callback_run_{false};
1130 
1132 
1134  Option(std::string name,
1135  std::string description = "",
1136  std::function<bool(results_t)> callback = [](results_t) { return true; },
1137  bool default_ = true,
1138  App *parent = nullptr)
1139  : description_(std::move(description)), default_(default_), parent_(parent), callback_(std::move(callback)) {
1140  std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(name));
1141  }
1142 
1143  public:
1146 
1148  size_t count() const { return results_.size(); }
1149 
1151  operator bool() const { return count() > 0; }
1152 
1154  void clear() { results_.clear(); }
1155 
1159 
1161  Option *expected(int value) {
1162  if(expected_ == value)
1163  return this;
1164  else if(value == 0)
1165  throw IncorrectConstruction::Set0Opt(single_name());
1166  else if(!changeable_)
1167  throw IncorrectConstruction::ChangeNotVector(single_name());
1168  else if(value != 1 && multi_option_policy_ != MultiOptionPolicy::Throw)
1169  throw IncorrectConstruction::AfterMultiOpt(single_name());
1170 
1171  expected_ = value;
1172  return this;
1173  }
1174 
1176  Option *check(std::function<std::string(const std::string &)> validator) {
1177  validators_.emplace_back(validator);
1178  return this;
1179  }
1180 
1182  Option *transform(std::function<std::string(std::string)> func) {
1183  validators_.emplace_back([func](std::string &inout) {
1184  try {
1185  inout = func(inout);
1186  } catch(const ValidationError &e) {
1187  return std::string(e.what());
1188  }
1189  return std::string();
1190  });
1191  return this;
1192  }
1193 
1195  Option *needs(Option *opt) {
1196  auto tup = requires_.insert(opt);
1197  if(!tup.second)
1198  throw OptionAlreadyAdded::Requires(get_name(), opt->get_name());
1199  return this;
1200  }
1201 
1203  template <typename T = App> Option *needs(std::string opt_name) {
1204  for(const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
1205  if(opt.get() != this && opt->check_name(opt_name))
1206  return needs(opt.get());
1207  throw IncorrectConstruction::MissingOption(opt_name);
1208  }
1209 
1211  template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
1212  needs(opt);
1213  return needs(opt1, args...);
1214  }
1215 
1216 #if __cplusplus <= 201703L
1217  Option *requires(Option *opt) { return needs(opt); }
1219 
1221  template <typename T = App> Option *requires(std::string opt_name) { return needs<T>(opt_name); }
1222 
1224  template <typename A, typename B, typename... ARG> Option *requires(A opt, B opt1, ARG... args) {
1225  needs(opt);
1226  return needs(opt1, args...);
1227  }
1228 #endif
1229 
1231  Option *excludes(Option *opt) {
1232  auto tup = excludes_.insert(opt);
1233  if(!tup.second)
1234  throw OptionAlreadyAdded::Excludes(get_name(), opt->get_name());
1235  return this;
1236  }
1237 
1239  template <typename T = App> Option *excludes(std::string opt_name) {
1240  for(const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
1241  if(opt.get() != this && opt->check_name(opt_name))
1242  return excludes(opt.get());
1243  throw IncorrectConstruction::MissingOption(opt_name);
1244  }
1245 
1247  template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
1248  excludes(opt);
1249  return excludes(opt1, args...);
1250  }
1251 
1253  Option *envname(std::string name) {
1254  envname_ = name;
1255  return this;
1256  }
1257 
1262  template <typename T = App> Option *ignore_case(bool value = true) {
1263  ignore_case_ = value;
1264  auto *parent = dynamic_cast<T *>(parent_);
1265 
1266  for(const Option_p &opt : parent->options_)
1267  if(opt.get() != this && *opt == *this)
1268  throw OptionAlreadyAdded(opt->get_name());
1269 
1270  return this;
1271  }
1272 
1274  Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
1275  if(get_expected() != 0 && get_expected() != 1)
1276  throw IncorrectConstruction::MultiOptionPolicy(single_name());
1277  multi_option_policy_ = value;
1278  return this;
1279  }
1280 
1284 
1286  int get_expected() const { return expected_; }
1287 
1289  int get_default() const { return default_; }
1290 
1292  bool get_positional() const { return pname_.length() > 0; }
1293 
1295  bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; }
1296 
1298  bool has_description() const { return description_.length() > 0; }
1299 
1301  const std::string &get_description() const { return description_; }
1302 
1303  // Just the pname
1304  std::string get_pname() const { return pname_; }
1305 
1309 
1311  std::string get_name(bool opt_only = false) const {
1312  std::vector<std::string> name_list;
1313  if(!opt_only && pname_.length() > 0)
1314  name_list.push_back(pname_);
1315  for(const std::string &sname : snames_)
1316  name_list.push_back("-" + sname);
1317  for(const std::string &lname : lnames_)
1318  name_list.push_back("--" + lname);
1319  return detail::join(name_list);
1320  }
1321 
1323  std::string help_positional() const {
1324  std::string out = pname_;
1325  if(get_expected() > 1)
1326  out = out + "(" + std::to_string(get_expected()) + "x)";
1327  else if(get_expected() == -1)
1328  out = out + "...";
1329  out = get_required() ? out : "[" + out + "]";
1330  return out;
1331  }
1332 
1334  std::string single_name() const {
1335  if(!lnames_.empty())
1336  return std::string("--") + lnames_[0];
1337  else if(!snames_.empty())
1338  return std::string("-") + snames_[0];
1339  else
1340  return pname_;
1341  }
1342 
1344  std::string help_name(bool opt_only = false) const {
1345  std::stringstream out;
1346  out << get_name(opt_only) << help_aftername();
1347  return out.str();
1348  }
1349 
1351  std::string help_pname() const {
1352  std::stringstream out;
1353  out << get_pname() << help_aftername();
1354  return out.str();
1355  }
1356 
1358  std::string help_aftername() const {
1359  std::stringstream out;
1360 
1361  if(get_expected() != 0) {
1362  if(!typeval_.empty())
1363  out << " " << typeval_;
1364  if(!defaultval_.empty())
1365  out << "=" << defaultval_;
1366  if(get_expected() > 1)
1367  out << " x " << get_expected();
1368  if(get_expected() == -1)
1369  out << " ...";
1370  }
1371  if(!envname_.empty())
1372  out << " (env:" << envname_ << ")";
1373  if(!requires_.empty()) {
1374  out << " Requires:";
1375  for(const Option *opt : requires_)
1376  out << " " << opt->get_name();
1377  }
1378  if(!excludes_.empty()) {
1379  out << " Excludes:";
1380  for(const Option *opt : excludes_)
1381  out << " " << opt->get_name();
1382  }
1383  return out.str();
1384  }
1385 
1389 
1391  void run_callback() {
1392 
1393  // Run the validators (can change the string)
1394  if(!validators_.empty()) {
1395  for(std::string &result : results_)
1396  for(const std::function<std::string(std::string &)> &vali : validators_) {
1397  std::string err_msg = vali(result);
1398  if(!err_msg.empty())
1399  throw ValidationError(single_name(), err_msg);
1400  }
1401  }
1402 
1403  bool local_result;
1404 
1405  // Operation depends on the policy setting
1406  if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
1407  results_t partial_result = {results_.back()};
1408  local_result = !callback_(partial_result);
1409  } else if(multi_option_policy_ == MultiOptionPolicy::TakeFirst) {
1410  results_t partial_result = {results_.at(0)};
1411  local_result = !callback_(partial_result);
1412  } else if(multi_option_policy_ == MultiOptionPolicy::Join) {
1413  results_t partial_result = {detail::join(results_, "\n")};
1414  local_result = !callback_(partial_result);
1415  } else {
1416  if((expected_ > 0 && results_.size() != static_cast<size_t>(expected_)) ||
1417  (expected_ < 0 && results_.size() < static_cast<size_t>(-expected_)))
1418  throw ArgumentMismatch(single_name(), expected_, results_.size());
1419  else
1420  local_result = !callback_(results_);
1421  }
1422 
1423  if(local_result)
1424  throw ConversionError(get_name(), results_);
1425  }
1426 
1428  bool operator==(const Option &other) const {
1429  for(const std::string &sname : snames_)
1430  if(other.check_sname(sname))
1431  return true;
1432  for(const std::string &lname : lnames_)
1433  if(other.check_lname(lname))
1434  return true;
1435  // We need to do the inverse, just in case we are ignore_case
1436  for(const std::string &sname : other.snames_)
1437  if(check_sname(sname))
1438  return true;
1439  for(const std::string &lname : other.lnames_)
1440  if(check_lname(lname))
1441  return true;
1442  return false;
1443  }
1444 
1446  bool check_name(std::string name) const {
1447 
1448  if(name.length() > 2 && name.substr(0, 2) == "--")
1449  return check_lname(name.substr(2));
1450  else if(name.length() > 1 && name.substr(0, 1) == "-")
1451  return check_sname(name.substr(1));
1452  else {
1453  std::string local_pname = pname_;
1454  if(ignore_case_) {
1455  local_pname = detail::to_lower(local_pname);
1456  name = detail::to_lower(name);
1457  }
1458  return name == local_pname;
1459  }
1460  }
1461 
1463  bool check_sname(std::string name) const {
1464  if(ignore_case_) {
1465  name = detail::to_lower(name);
1466  return std::find_if(std::begin(snames_), std::end(snames_), [&name](std::string local_sname) {
1467  return detail::to_lower(local_sname) == name;
1468  }) != std::end(snames_);
1469  } else
1470  return std::find(std::begin(snames_), std::end(snames_), name) != std::end(snames_);
1471  }
1472 
1474  bool check_lname(std::string name) const {
1475  if(ignore_case_) {
1476  name = detail::to_lower(name);
1477  return std::find_if(std::begin(lnames_), std::end(lnames_), [&name](std::string local_sname) {
1478  return detail::to_lower(local_sname) == name;
1479  }) != std::end(lnames_);
1480  } else
1481  return std::find(std::begin(lnames_), std::end(lnames_), name) != std::end(lnames_);
1482  }
1483 
1485  void add_result(std::string s) {
1486  results_.push_back(s);
1487  callback_run_ = false;
1488  }
1489 
1491  std::vector<std::string> results() const { return results_; }
1492 
1494  bool get_callback_run() const { return callback_run_; }
1495 
1499 
1501  void set_custom_option(std::string typeval, int expected = 1) {
1502  typeval_ = typeval;
1503  expected_ = expected;
1504  if(expected == 0)
1505  required_ = false;
1506  changeable_ = expected < 0;
1507  }
1508 
1510  void set_default_str(std::string val) { defaultval_ = val; }
1511 
1513  void set_default_val(std::string val) {
1514  set_default_str(val);
1515  auto old_results = results_;
1516  results_ = {val};
1517  run_callback();
1518  results_ = std::move(old_results);
1519  }
1520 
1522  void set_type_name(std::string val) { typeval_ = val; }
1523 
1525  std::string get_type_name() const { return typeval_; }
1526 
1528 
1529  protected:
1533  bool _has_help_positional() const {
1534  return get_positional() && (has_description() || !requires_.empty() || !excludes_.empty());
1535  }
1537 };
1538 
1539 } // namespace CLI
1540 
1541 // From CLI/App.hpp
1542 
1543 namespace CLI {
1544 
1545 #ifndef CLI11_PARSE
1546 #define CLI11_PARSE(app, argc, argv) \
1547  try { \
1548  (app).parse((argc), (argv)); \
1549  } catch(const CLI::ParseError &e) { \
1550  return (app).exit(e); \
1551  }
1552 #endif
1553 
1554 namespace detail {
1555 enum class Classifer { NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND };
1556 struct AppFriend;
1557 } // namespace detail
1558 
1559 namespace FailureMessage {
1560 std::string simple(const App *app, const Error &e);
1561 std::string help(const App *app, const Error &e);
1562 } // namespace FailureMessage
1563 
1564 class App;
1565 
1566 using App_p = std::unique_ptr<App>;
1567 
1569 
1572 class App final {
1573  friend Option;
1574  friend detail::AppFriend;
1575 
1576  protected:
1577  // This library follows the Google style guide for member names ending in underscores
1578 
1581 
1583  std::string name_{"program"};
1584 
1586  std::string description_;
1587 
1589  bool allow_extras_{false};
1590 
1592  bool allow_ini_extras_{false};
1593 
1595  bool prefix_command_{false};
1596 
1598  std::function<void()> callback_;
1599 
1603 
1605  OptionDefaults option_defaults_;
1606 
1608  std::vector<Option_p> options_;
1609 
1613 
1615  std::string footer_;
1616 
1618  Option *help_ptr_{nullptr};
1619 
1621  std::function<std::string(const App *, const Error &e)> failure_message_ = FailureMessage::simple;
1622 
1626 
1627  using missing_t = std::vector<std::pair<detail::Classifer, std::string>>;
1628 
1632  missing_t missing_;
1633 
1635  std::vector<Option *> parse_order_;
1636 
1638  std::vector<App *> parsed_subcommands_;
1639 
1643 
1645  std::vector<App_p> subcommands_;
1646 
1648  bool ignore_case_{false};
1649 
1651  bool fallthrough_{false};
1652 
1654  App *parent_{nullptr};
1655 
1657  bool parsed_{false};
1658 
1660  size_t require_subcommand_min_ = 0;
1661 
1663  size_t require_subcommand_max_ = 0;
1664 
1666  std::string group_{"Subcommands"};
1667 
1671 
1673  std::string config_name_;
1674 
1676  bool config_required_{false};
1677 
1679  Option *config_ptr_{nullptr};
1680 
1682 
1684  App(std::string description_, App *parent) : description_(std::move(description_)), parent_(parent) {
1685  // Inherit if not from a nullptr
1686  if(parent_ != nullptr) {
1687  if(parent_->help_ptr_ != nullptr)
1688  set_help_flag(parent_->help_ptr_->get_name(), parent_->help_ptr_->get_description());
1689 
1691  option_defaults_ = parent_->option_defaults_;
1692 
1693  // INHERITABLE
1694  failure_message_ = parent_->failure_message_;
1695  allow_extras_ = parent_->allow_extras_;
1696  allow_ini_extras_ = parent_->allow_ini_extras_;
1697  prefix_command_ = parent_->prefix_command_;
1698  ignore_case_ = parent_->ignore_case_;
1699  fallthrough_ = parent_->fallthrough_;
1700  group_ = parent_->group_;
1701  footer_ = parent_->footer_;
1702  require_subcommand_max_ = parent_->require_subcommand_max_;
1703  }
1704  }
1705 
1706  public:
1709 
1711  App(std::string description_ = "") : App(description_, nullptr) {
1712  set_help_flag("-h,--help", "Print this help message and exit");
1713  }
1714 
1721  App *set_callback(std::function<void()> callback) {
1722  callback_ = callback;
1723  return this;
1724  }
1725 
1727  App *allow_extras(bool allow = true) {
1728  allow_extras_ = allow;
1729  return this;
1730  }
1731 
1734  App *allow_ini_extras(bool allow = true) {
1735  allow_extras(allow);
1736  allow_ini_extras_ = allow;
1737  return this;
1738  }
1739 
1741  App *prefix_command(bool allow = true) {
1742  prefix_command_ = allow;
1743  return this;
1744  }
1745 
1747  App *ignore_case(bool value = true) {
1748  ignore_case_ = value;
1749  if(parent_ != nullptr) {
1750  for(const auto &subc : parent_->subcommands_) {
1751  if(subc.get() != this && (this->check_name(subc->name_) || subc->check_name(this->name_)))
1752  throw OptionAlreadyAdded(subc->name_);
1753  }
1754  }
1755  return this;
1756  }
1757 
1759  bool parsed() const { return parsed_; }
1760 
1762  OptionDefaults *option_defaults() { return &option_defaults_; }
1763 
1767 
1782  Option *add_option(std::string name, callback_t callback, std::string description = "", bool defaulted = false) {
1783  Option myopt{name, description, callback, defaulted, this};
1784 
1785  if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) {
1786  return *v == myopt;
1787  }) == std::end(options_)) {
1788  options_.emplace_back();
1789  Option_p &option = options_.back();
1790  option.reset(new Option(name, description, callback, defaulted, this));
1791  option_defaults_.copy_to(option.get());
1792  return option.get();
1793  } else
1794  throw OptionAlreadyAdded(myopt.get_name());
1795  }
1796 
1798  template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy>
1799  Option *add_option(std::string name,
1800  T &variable,
1801  std::string description = "") {
1802 
1803  std::string simple_name = CLI::detail::split(name, ',').at(0);
1804  CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) {
1805  return detail::lexical_cast(res[0], variable);
1806  };
1807 
1808  Option *opt = add_option(name, fun, description, false);
1809  opt->set_custom_option(detail::type_name<T>());
1810  return opt;
1811  }
1812 
1814  template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy>
1815  Option *add_option(std::string name,
1816  T &variable,
1817  std::string description,
1818  bool defaulted) {
1819 
1820  std::string simple_name = CLI::detail::split(name, ',').at(0);
1821  CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) {
1822  return detail::lexical_cast(res[0], variable);
1823  };
1824 
1825  Option *opt = add_option(name, fun, description, defaulted);
1826  opt->set_custom_option(detail::type_name<T>());
1827  if(defaulted) {
1828  std::stringstream out;
1829  out << variable;
1830  opt->set_default_str(out.str());
1831  }
1832  return opt;
1833  }
1834 
1836  template <typename T>
1837  Option *add_option(std::string name,
1838  std::vector<T> &variable,
1839  std::string description = "") {
1840 
1841  CLI::callback_t fun = [&variable](CLI::results_t res) {
1842  bool retval = true;
1843  variable.clear();
1844  for(const auto &a : res) {
1845  variable.emplace_back();
1846  retval &= detail::lexical_cast(a, variable.back());
1847  }
1848  return (!variable.empty()) && retval;
1849  };
1850 
1851  Option *opt = add_option(name, fun, description, false);
1852  opt->set_custom_option(detail::type_name<T>(), -1);
1853  return opt;
1854  }
1855 
1857  template <typename T>
1858  Option *add_option(std::string name,
1859  std::vector<T> &variable,
1860  std::string description,
1861  bool defaulted) {
1862 
1863  CLI::callback_t fun = [&variable](CLI::results_t res) {
1864  bool retval = true;
1865  variable.clear();
1866  for(const auto &a : res) {
1867  variable.emplace_back();
1868  retval &= detail::lexical_cast(a, variable.back());
1869  }
1870  return (!variable.empty()) && retval;
1871  };
1872 
1873  Option *opt = add_option(name, fun, description, defaulted);
1874  opt->set_custom_option(detail::type_name<T>(), -1);
1875  if(defaulted)
1876  opt->set_default_str("[" + detail::join(variable) + "]");
1877  return opt;
1878  }
1879 
1881  Option *set_help_flag(std::string name = "", std::string description = "") {
1882  if(help_ptr_ != nullptr) {
1883  remove_option(help_ptr_);
1884  help_ptr_ = nullptr;
1885  }
1886 
1887  // Empty name will simply remove the help flag
1888  if(!name.empty()) {
1889  help_ptr_ = add_flag(name, description);
1890  help_ptr_->configurable(false);
1891  }
1892 
1893  return help_ptr_;
1894  }
1895 
1897  Option *add_flag(std::string name, std::string description = "") {
1898  CLI::callback_t fun = [](CLI::results_t) { return true; };
1899 
1900  Option *opt = add_option(name, fun, description, false);
1901  if(opt->get_positional())
1902  throw IncorrectConstruction::PositionalFlag(name);
1903  opt->set_custom_option("", 0);
1904  return opt;
1905  }
1906 
1908  template <typename T,
1910  Option *add_flag(std::string name,
1911  T &count,
1912  std::string description = "") {
1913 
1914  count = 0;
1915  CLI::callback_t fun = [&count](CLI::results_t res) {
1916  count = static_cast<T>(res.size());
1917  return true;
1918  };
1919 
1920  Option *opt = add_option(name, fun, description, false);
1921  if(opt->get_positional())
1922  throw IncorrectConstruction::PositionalFlag(name);
1923  opt->set_custom_option("", 0);
1924  return opt;
1925  }
1926 
1929  template <typename T, enable_if_t<is_bool<T>::value, detail::enabler> = detail::dummy>
1930  Option *add_flag(std::string name,
1931  T &count,
1932  std::string description = "") {
1933 
1934  count = false;
1935  CLI::callback_t fun = [&count](CLI::results_t res) {
1936  count = true;
1937  return res.size() == 1;
1938  };
1939 
1940  Option *opt = add_option(name, fun, description, false);
1941  if(opt->get_positional())
1942  throw IncorrectConstruction::PositionalFlag(name);
1943  opt->set_custom_option("", 0);
1944  opt->multi_option_policy(CLI::MultiOptionPolicy::TakeLast);
1945  return opt;
1946  }
1947 
1949  Option *add_flag_function(std::string name,
1950  std::function<void(size_t)> function,
1951  std::string description = "") {
1952 
1953  CLI::callback_t fun = [function](CLI::results_t res) {
1954  auto count = static_cast<size_t>(res.size());
1955  function(count);
1956  return true;
1957  };
1958 
1959  Option *opt = add_option(name, fun, description, false);
1960  if(opt->get_positional())
1961  throw IncorrectConstruction::PositionalFlag(name);
1962  opt->set_custom_option("", 0);
1963  return opt;
1964  }
1965 
1966 #if __cplusplus >= 201402L
1967  Option *add_flag(std::string name,
1969  std::function<void(size_t)> function,
1970  std::string description = "") {
1971  return add_flag_function(name, function, description);
1972  }
1973 #endif
1974 
1976  template <typename T>
1977  Option *add_set(std::string name,
1978  T &member,
1979  std::set<T> options,
1980  std::string description = "") {
1981 
1982  std::string simple_name = CLI::detail::split(name, ',').at(0);
1983  CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
1984  bool retval = detail::lexical_cast(res[0], member);
1985  if(!retval)
1986  throw ConversionError(res[0], simple_name);
1987  return std::find(std::begin(options), std::end(options), member) != std::end(options);
1988  };
1989 
1990  Option *opt = add_option(name, fun, description, false);
1991  std::string typeval = detail::type_name<T>();
1992  typeval += " in {" + detail::join(options) + "}";
1993  opt->set_custom_option(typeval);
1994  return opt;
1995  }
1996 
1998  template <typename T>
1999  Option *add_set(std::string name,
2000  T &member,
2001  std::set<T> options,
2002  std::string description,
2003  bool defaulted) {
2004 
2005  std::string simple_name = CLI::detail::split(name, ',').at(0);
2006  CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2007  bool retval = detail::lexical_cast(res[0], member);
2008  if(!retval)
2009  throw ConversionError(res[0], simple_name);
2010  return std::find(std::begin(options), std::end(options), member) != std::end(options);
2011  };
2012 
2013  Option *opt = add_option(name, fun, description, defaulted);
2014  std::string typeval = detail::type_name<T>();
2015  typeval += " in {" + detail::join(options) + "}";
2016  opt->set_custom_option(typeval);
2017  if(defaulted) {
2018  std::stringstream out;
2019  out << member;
2020  opt->set_default_str(out.str());
2021  }
2022  return opt;
2023  }
2024 
2026  Option *add_set_ignore_case(std::string name,
2027  std::string &member,
2028  std::set<std::string> options,
2029  std::string description = "") {
2030 
2031  std::string simple_name = CLI::detail::split(name, ',').at(0);
2032  CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2033  member = detail::to_lower(res[0]);
2034  auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2035  return detail::to_lower(val) == member;
2036  });
2037  if(iter == std::end(options))
2038  throw ConversionError(member, simple_name);
2039  else {
2040  member = *iter;
2041  return true;
2042  }
2043  };
2044 
2045  Option *opt = add_option(name, fun, description, false);
2046  std::string typeval = detail::type_name<std::string>();
2047  typeval += " in {" + detail::join(options) + "}";
2048  opt->set_custom_option(typeval);
2049 
2050  return opt;
2051  }
2052 
2054  Option *add_set_ignore_case(std::string name,
2055  std::string &member,
2056  std::set<std::string> options,
2057  std::string description,
2058  bool defaulted) {
2059 
2060  std::string simple_name = CLI::detail::split(name, ',').at(0);
2061  CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2062  member = detail::to_lower(res[0]);
2063  auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2064  return detail::to_lower(val) == member;
2065  });
2066  if(iter == std::end(options))
2067  throw ConversionError(member, simple_name);
2068  else {
2069  member = *iter;
2070  return true;
2071  }
2072  };
2073 
2074  Option *opt = add_option(name, fun, description, defaulted);
2075  std::string typeval = detail::type_name<std::string>();
2076  typeval += " in {" + detail::join(options) + "}";
2077  opt->set_custom_option(typeval);
2078  if(defaulted) {
2079  opt->set_default_str(member);
2080  }
2081  return opt;
2082  }
2083 
2085  template <typename T>
2086  Option *add_complex(std::string name,
2087  T &variable,
2088  std::string description = "",
2089  bool defaulted = false,
2090  std::string label = "COMPLEX") {
2091 
2092  std::string simple_name = CLI::detail::split(name, ',').at(0);
2093  CLI::callback_t fun = [&variable, simple_name, label](results_t res) {
2094  if(res[1].back() == 'i')
2095  res[1].pop_back();
2096  double x, y;
2097  bool worked = detail::lexical_cast(res[0], x) && detail::lexical_cast(res[1], y);
2098  if(worked)
2099  variable = T(x, y);
2100  return worked;
2101  };
2102 
2103  CLI::Option *opt = add_option(name, fun, description, defaulted);
2104  opt->set_custom_option(label, 2);
2105  if(defaulted) {
2106  std::stringstream out;
2107  out << variable;
2108  opt->set_default_str(out.str());
2109  }
2110  return opt;
2111  }
2112 
2114  Option *set_config(std::string name = "",
2115  std::string default_filename = "",
2116  std::string help = "Read an ini file",
2117  bool required = false) {
2118 
2119  // Remove existing config if present
2120  if(config_ptr_ != nullptr)
2121  remove_option(config_ptr_);
2122 
2123  // Only add config if option passed
2124  if(!name.empty()) {
2125  config_name_ = default_filename;
2126  config_required_ = required;
2127  config_ptr_ = add_option(name, config_name_, help, !default_filename.empty());
2128  config_ptr_->configurable(false);
2129  }
2130 
2131  return config_ptr_;
2132  }
2133 
2135  bool remove_option(Option *opt) {
2136  auto iterator =
2137  std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
2138  if(iterator != std::end(options_)) {
2139  options_.erase(iterator);
2140  return true;
2141  }
2142  return false;
2143  }
2144 
2148 
2150  App *add_subcommand(std::string name, std::string description = "") {
2151  subcommands_.emplace_back(new App(description, this));
2152  subcommands_.back()->name_ = name;
2153  for(const auto &subc : subcommands_)
2154  if(subc.get() != subcommands_.back().get())
2155  if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
2156  throw OptionAlreadyAdded(subc->name_);
2157  return subcommands_.back().get();
2158  }
2159 
2161  App *get_subcommand(App *subcom) const {
2162  for(const App_p &subcomptr : subcommands_)
2163  if(subcomptr.get() == subcom)
2164  return subcom;
2165  throw OptionNotFound(subcom->get_name());
2166  }
2167 
2169  App *get_subcommand(std::string subcom) const {
2170  for(const App_p &subcomptr : subcommands_)
2171  if(subcomptr->check_name(subcom))
2172  return subcomptr.get();
2173  throw OptionNotFound(subcom);
2174  }
2175 
2177  App *group(std::string name) {
2178  group_ = name;
2179  return this;
2180  }
2181 
2183  App *require_subcommand() {
2184  require_subcommand_min_ = 1;
2185  require_subcommand_max_ = 0;
2186  return this;
2187  }
2188 
2192  App *require_subcommand(int value) {
2193  if(value < 0) {
2194  require_subcommand_min_ = 0;
2195  require_subcommand_max_ = static_cast<size_t>(-value);
2196  } else {
2197  require_subcommand_min_ = static_cast<size_t>(value);
2198  require_subcommand_max_ = static_cast<size_t>(value);
2199  }
2200  return this;
2201  }
2202 
2205  App *require_subcommand(size_t min, size_t max) {
2206  require_subcommand_min_ = min;
2207  require_subcommand_max_ = max;
2208  return this;
2209  }
2210 
2213  App *fallthrough(bool value = true) {
2214  fallthrough_ = value;
2215  return this;
2216  }
2217 
2220  operator bool() const { return parsed_; }
2221 
2225 
2229  virtual void pre_callback() {}
2230 
2234 
2237  void parse(int argc, char **argv) {
2238  name_ = argv[0];
2239  std::vector<std::string> args;
2240  for(int i = argc - 1; i > 0; i--)
2241  args.emplace_back(argv[i]);
2242  parse(args);
2243  }
2244 
2247  void parse(std::vector<std::string> &args) {
2248  _validate();
2249  _parse(args);
2250  run_callback();
2251  }
2252 
2254  void set_failure_message(std::function<std::string(const App *, const Error &e)> function) {
2255  failure_message_ = function;
2256  }
2257 
2259  int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {
2260 
2262  if(dynamic_cast<const CLI::RuntimeError *>(&e) != nullptr)
2263  return e.get_exit_code();
2264 
2265  if(dynamic_cast<const CLI::CallForHelp *>(&e) != nullptr) {
2266  out << help();
2267  return e.get_exit_code();
2268  }
2269 
2270  if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
2271  if(failure_message_)
2272  err << failure_message_(this, e) << std::flush;
2273  }
2274 
2275  return e.get_exit_code();
2276  }
2277 
2279  void reset() {
2280 
2281  parsed_ = false;
2282  missing_.clear();
2283  parsed_subcommands_.clear();
2284 
2285  for(const Option_p &opt : options_) {
2286  opt->clear();
2287  }
2288  for(const App_p &app : subcommands_) {
2289  app->reset();
2290  }
2291  }
2292 
2296 
2298  size_t count(std::string name) const {
2299  for(const Option_p &opt : options_) {
2300  if(opt->check_name(name)) {
2301  return opt->count();
2302  }
2303  }
2304  throw OptionNotFound(name);
2305  }
2306 
2309  std::vector<App *> get_subcommands(bool parsed = true) const {
2310  if(parsed) {
2311  return parsed_subcommands_;
2312  } else {
2313  std::vector<App *> subcomms(subcommands_.size());
2314  std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
2315  return v.get();
2316  });
2317  return subcomms;
2318  }
2319  }
2320 
2322  bool got_subcommand(App *subcom) const {
2323  // get subcom needed to verify that this was a real subcommand
2324  return get_subcommand(subcom)->parsed_;
2325  }
2326 
2328  bool got_subcommand(std::string name) const { return get_subcommand(name)->parsed_; }
2329 
2333 
2335  App *set_footer(std::string footer) {
2336  footer_ = footer;
2337  return this;
2338  }
2339 
2342  std::string
2343  config_to_str(bool default_also = false, std::string prefix = "", bool write_description = false) const {
2344  std::stringstream out;
2345  for(const Option_p &opt : options_) {
2346 
2347  // Only process option with a long-name and configurable
2348  if(!opt->lnames_.empty() && opt->get_configurable()) {
2349  std::string name = prefix + opt->lnames_[0];
2350  std::string value;
2351 
2352  // Non-flags
2353  if(opt->get_expected() != 0) {
2354 
2355  // If the option was found on command line
2356  if(opt->count() > 0)
2357  value = detail::inijoin(opt->results());
2358 
2359  // If the option has a default and is requested by optional argument
2360  else if(default_also && !opt->defaultval_.empty())
2361  value = opt->defaultval_;
2362  // Flag, one passed
2363  } else if(opt->count() == 1) {
2364  value = "true";
2365 
2366  // Flag, multiple passed
2367  } else if(opt->count() > 1) {
2368  value = std::to_string(opt->count());
2369 
2370  // Flag, not present
2371  } else if(opt->count() == 0 && default_also) {
2372  value = "false";
2373  }
2374 
2375  if(!value.empty()) {
2376  if(write_description && opt->has_description()) {
2377  if(static_cast<int>(out.tellp()) != 0) {
2378  out << std::endl;
2379  }
2380  out << "; " << detail::fix_newlines("; ", opt->get_description()) << std::endl;
2381  }
2382  out << name << "=" << value << std::endl;
2383  }
2384  }
2385  }
2386  for(const App_p &subcom : subcommands_)
2387  out << subcom->config_to_str(default_also, prefix + subcom->name_ + ".");
2388  return out.str();
2389  }
2390 
2392  std::string help(size_t wid = 30, std::string prev = "") const {
2393  // Delegate to subcommand if needed
2394  if(prev.empty())
2395  prev = name_;
2396  else
2397  prev += " " + name_;
2398 
2399  auto selected_subcommands = get_subcommands();
2400  if(!selected_subcommands.empty())
2401  return selected_subcommands.at(0)->help(wid, prev);
2402 
2403  std::stringstream out;
2404  out << description_ << std::endl;
2405  out << "Usage: " << prev;
2406 
2407  // Check for options_
2408  bool npos = false;
2409  std::set<std::string> groups;
2410  for(const Option_p &opt : options_) {
2411  if(opt->nonpositional()) {
2412  npos = true;
2413  groups.insert(opt->get_group());
2414  }
2415  }
2416 
2417  if(npos)
2418  out << " [OPTIONS]";
2419 
2420  // Positionals
2421  bool pos = false;
2422  for(const Option_p &opt : options_)
2423  if(opt->get_positional()) {
2424  // A hidden positional should still show up in the usage statement
2425  // if(detail::to_lower(opt->get_group()).empty())
2426  // continue;
2427  out << " " << opt->help_positional();
2428  if(opt->_has_help_positional())
2429  pos = true;
2430  }
2431 
2432  if(!subcommands_.empty()) {
2433  if(require_subcommand_min_ > 0)
2434  out << " SUBCOMMAND";
2435  else
2436  out << " [SUBCOMMAND]";
2437  }
2438 
2439  out << std::endl;
2440 
2441  // Positional descriptions
2442  if(pos) {
2443  out << std::endl << "Positionals:" << std::endl;
2444  for(const Option_p &opt : options_) {
2445  if(detail::to_lower(opt->get_group()).empty())
2446  continue; // Hidden
2447  if(opt->_has_help_positional())
2448  detail::format_help(out, opt->help_pname(), opt->get_description(), wid);
2449  }
2450  }
2451 
2452  // Options
2453  if(npos) {
2454  for(const std::string &group : groups) {
2455  if(detail::to_lower(group).empty())
2456  continue; // Hidden
2457  out << std::endl << group << ":" << std::endl;
2458  for(const Option_p &opt : options_) {
2459  if(opt->nonpositional() && opt->get_group() == group)
2460  detail::format_help(out, opt->help_name(true), opt->get_description(), wid);
2461  }
2462  }
2463  }
2464 
2465  // Subcommands
2466  if(!subcommands_.empty()) {
2467  std::set<std::string> subcmd_groups_seen;
2468  for(const App_p &com : subcommands_) {
2469  const std::string &group_key = detail::to_lower(com->get_group());
2470  if(group_key.empty() || subcmd_groups_seen.count(group_key) != 0)
2471  continue; // Hidden or not in a group
2472 
2473  subcmd_groups_seen.insert(group_key);
2474  out << std::endl << com->get_group() << ":" << std::endl;
2475  for(const App_p &new_com : subcommands_)
2476  if(detail::to_lower(new_com->get_group()) == group_key)
2477  detail::format_help(out, new_com->get_name(), new_com->description_, wid);
2478  }
2479  }
2480 
2481  if(!footer_.empty()) {
2482  out << std::endl << footer_ << std::endl;
2483  }
2484 
2485  return out.str();
2486  }
2487 
2491 
2493  bool get_ignore_case() const { return ignore_case_; }
2494 
2496  bool get_fallthrough() const { return fallthrough_; }
2497 
2499  const std::string &get_group() const { return group_; }
2500 
2502  std::string get_footer() const { return footer_; }
2503 
2505  size_t get_require_subcommand_min() const { return require_subcommand_min_; }
2506 
2508  size_t get_require_subcommand_max() const { return require_subcommand_max_; }
2509 
2511  bool get_prefix_command() const { return prefix_command_; }
2512 
2514  bool get_allow_extras() const { return allow_extras_; }
2515 
2517  bool get_allow_ini_extras() const { return allow_ini_extras_; }
2518 
2520  Option *get_help_ptr() { return help_ptr_; }
2521 
2523  const Option *get_help_ptr() const { return help_ptr_; }
2524 
2526  Option *get_config_ptr() { return config_ptr_; }
2527 
2529  App *get_parent() { return parent_; }
2530 
2532  const Option *get_config_ptr() const { return config_ptr_; }
2534  std::string get_name() const { return name_; }
2535 
2537  bool check_name(std::string name_to_check) const {
2538  std::string local_name = name_;
2539  if(ignore_case_) {
2540  local_name = detail::to_lower(name_);
2541  name_to_check = detail::to_lower(name_to_check);
2542  }
2543 
2544  return local_name == name_to_check;
2545  }
2546 
2548  const std::vector<Option *> &parse_order() const { return parse_order_; }
2549 
2551  std::vector<std::string> remaining(bool recurse = false) const {
2552  std::vector<std::string> miss_list;
2553  for(const std::pair<detail::Classifer, std::string> &miss : missing_) {
2554  miss_list.push_back(std::get<1>(miss));
2555  }
2556  if(recurse) {
2557  for(const App *sub : parsed_subcommands_) {
2558  std::vector<std::string> output = sub->remaining(recurse);
2559  std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
2560  }
2561  }
2562  return miss_list;
2563  }
2564 
2566  size_t remaining_size(bool recurse = false) const {
2567  size_t count = std::count_if(
2568  std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifer, std::string> &val) {
2569  return val.first != detail::Classifer::POSITIONAL_MARK;
2570  });
2571  if(recurse) {
2572  for(const App_p &sub : subcommands_) {
2573  count += sub->remaining_size(recurse);
2574  }
2575  }
2576  return count;
2577  }
2578 
2580 
2581  protected:
2585  void _validate() const {
2586  auto count = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
2587  return opt->get_expected() == -1 && opt->get_positional();
2588  });
2589  if(count > 1)
2590  throw InvalidError(name_);
2591  for(const App_p &app : subcommands_)
2592  app->_validate();
2593  }
2594 
2596  void run_callback() {
2597  pre_callback();
2598  if(callback_)
2599  callback_();
2600  for(App *subc : get_subcommands()) {
2601  subc->run_callback();
2602  }
2603  }
2604 
2606  bool _valid_subcommand(const std::string &current) const {
2607  // Don't match if max has been reached - but still check parents
2608  if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
2609  return parent_ != nullptr && parent_->_valid_subcommand(current);
2610  }
2611 
2612  for(const App_p &com : subcommands_)
2613  if(com->check_name(current) && !*com)
2614  return true;
2615 
2616  // Check parent if exists, else return false
2617  return parent_ != nullptr && parent_->_valid_subcommand(current);
2618  }
2619 
2621  detail::Classifer _recognize(const std::string &current) const {
2622  std::string dummy1, dummy2;
2623 
2624  if(current == "--")
2625  return detail::Classifer::POSITIONAL_MARK;
2626  if(_valid_subcommand(current))
2627  return detail::Classifer::SUBCOMMAND;
2628  if(detail::split_long(current, dummy1, dummy2))
2629  return detail::Classifer::LONG;
2630  if(detail::split_short(current, dummy1, dummy2))
2631  return detail::Classifer::SHORT;
2632  return detail::Classifer::NONE;
2633  }
2634 
2636  void _parse(std::vector<std::string> &args) {
2637  parsed_ = true;
2638  bool positional_only = false;
2639 
2640  while(!args.empty()) {
2641  _parse_single(args, positional_only);
2642  }
2643 
2644  if(help_ptr_ != nullptr && help_ptr_->count() > 0) {
2645  throw CallForHelp();
2646  }
2647 
2648  // Process an INI file
2649  if(config_ptr_ != nullptr) {
2650  if(*config_ptr_) {
2651  config_ptr_->run_callback();
2652  config_required_ = true;
2653  }
2654  if(!config_name_.empty()) {
2655  try {
2656  std::vector<detail::ini_ret_t> values = detail::parse_ini(config_name_);
2657  while(!values.empty()) {
2658  if(!_parse_ini(values)) {
2659  throw INIError::Extras(values.back().fullname);
2660  }
2661  }
2662  } catch(const FileError &) {
2663  if(config_required_)
2664  throw;
2665  }
2666  }
2667  }
2668 
2669  // Get envname options if not yet passed
2670  for(const Option_p &opt : options_) {
2671  if(opt->count() == 0 && !opt->envname_.empty()) {
2672  char *buffer = nullptr;
2673  std::string ename_string;
2674 
2675 #ifdef _MSC_VER
2676  // Windows version
2677  size_t sz = 0;
2678  if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {
2679  ename_string = std::string(buffer);
2680  free(buffer);
2681  }
2682 #else
2683  // This also works on Windows, but gives a warning
2684  buffer = std::getenv(opt->envname_.c_str());
2685  if(buffer != nullptr)
2686  ename_string = std::string(buffer);
2687 #endif
2688 
2689  if(!ename_string.empty()) {
2690  opt->add_result(ename_string);
2691  }
2692  }
2693  }
2694 
2695  // Process callbacks
2696  for(const Option_p &opt : options_) {
2697  if(opt->count() > 0 && !opt->get_callback_run()) {
2698  opt->run_callback();
2699  }
2700  }
2701 
2702  // Verify required options
2703  for(const Option_p &opt : options_) {
2704  // Required or partially filled
2705  if(opt->get_required() || opt->count() != 0) {
2706  // Make sure enough -N arguments parsed (+N is already handled in parsing function)
2707  if(opt->get_expected() < 0 && opt->count() < static_cast<size_t>(-opt->get_expected()))
2708  throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_expected());
2709 
2710  // Required but empty
2711  if(opt->get_required() && opt->count() == 0)
2712  throw RequiredError(opt->single_name());
2713  }
2714  // Requires
2715  for(const Option *opt_req : opt->requires_)
2716  if(opt->count() > 0 && opt_req->count() == 0)
2717  throw RequiresError(opt->single_name(), opt_req->single_name());
2718  // Excludes
2719  for(const Option *opt_ex : opt->excludes_)
2720  if(opt->count() > 0 && opt_ex->count() != 0)
2721  throw ExcludesError(opt->single_name(), opt_ex->single_name());
2722  }
2723 
2724  auto selected_subcommands = get_subcommands();
2725  if(require_subcommand_min_ > selected_subcommands.size())
2726  throw RequiredError::Subcommand(require_subcommand_min_);
2727 
2728  // Convert missing (pairs) to extras (string only)
2729  if(!(allow_extras_ || prefix_command_)) {
2730  size_t num_left_over = remaining_size();
2731  if(num_left_over > 0) {
2732  args = remaining(false);
2733  std::reverse(std::begin(args), std::end(args));
2734  throw ExtrasError(args);
2735  }
2736  }
2737  }
2738 
2743  bool _parse_ini(std::vector<detail::ini_ret_t> &args) {
2744  detail::ini_ret_t &current = args.back();
2745  std::string parent = current.parent(); // respects current.level
2746  std::string name = current.name();
2747 
2748  // If a parent is listed, go to a subcommand
2749  if(!parent.empty()) {
2750  current.level++;
2751  for(const App_p &com : subcommands_)
2752  if(com->check_name(parent))
2753  return com->_parse_ini(args);
2754  return false;
2755  }
2756 
2757  auto op_ptr = std::find_if(
2758  std::begin(options_), std::end(options_), [name](const Option_p &v) { return v->check_lname(name); });
2759 
2760  if(op_ptr == std::end(options_)) {
2761  if(allow_ini_extras_) {
2762  // Should we worry about classifying the extras properly?
2763  missing_.emplace_back(detail::Classifer::NONE, current.fullname);
2764  args.pop_back();
2765  return true;
2766  }
2767  return false;
2768  }
2769 
2770  // Let's not go crazy with pointer syntax
2771  Option_p &op = *op_ptr;
2772 
2773  if(!op->get_configurable())
2774  throw INIError::NotConfigurable(current.fullname);
2775 
2776  if(op->results_.empty()) {
2777  // Flag parsing
2778  if(op->get_expected() == 0) {
2779  if(current.inputs.size() == 1) {
2780  std::string val = current.inputs.at(0);
2781  val = detail::to_lower(val);
2782  if(val == "true" || val == "on" || val == "yes")
2783  op->results_ = {""};
2784  else if(val == "false" || val == "off" || val == "no")
2785  ;
2786  else
2787  try {
2788  size_t ui = std::stoul(val);
2789  for(size_t i = 0; i < ui; i++)
2790  op->results_.emplace_back("");
2791  } catch(const std::invalid_argument &) {
2792  throw ConversionError::TrueFalse(current.fullname);
2793  }
2794  } else
2795  throw ConversionError::TooManyInputsFlag(current.fullname);
2796  } else {
2797  op->results_ = current.inputs;
2798  op->run_callback();
2799  }
2800  }
2801 
2802  args.pop_back();
2803  return true;
2804  }
2805 
2808  void _parse_single(std::vector<std::string> &args, bool &positional_only) {
2809 
2810  detail::Classifer classifer = positional_only ? detail::Classifer::NONE : _recognize(args.back());
2811  switch(classifer) {
2812  case detail::Classifer::POSITIONAL_MARK:
2813  missing_.emplace_back(classifer, args.back());
2814  args.pop_back();
2815  positional_only = true;
2816  break;
2817  case detail::Classifer::SUBCOMMAND:
2818  _parse_subcommand(args);
2819  break;
2820  case detail::Classifer::LONG:
2821  // If already parsed a subcommand, don't accept options_
2822  _parse_arg(args, true);
2823  break;
2824  case detail::Classifer::SHORT:
2825  // If already parsed a subcommand, don't accept options_
2826  _parse_arg(args, false);
2827  break;
2828  case detail::Classifer::NONE:
2829  // Probably a positional or something for a parent (sub)command
2830  _parse_positional(args);
2831  }
2832  }
2833 
2835  size_t _count_remaining_positionals(bool required = false) const {
2836  size_t retval = 0;
2837  for(const Option_p &opt : options_)
2838  if(opt->get_positional() && (!required || opt->get_required()) && opt->get_expected() > 0 &&
2839  static_cast<int>(opt->count()) < opt->get_expected())
2840  retval = static_cast<size_t>(opt->get_expected()) - opt->count();
2841 
2842  return retval;
2843  }
2844 
2846  void _parse_positional(std::vector<std::string> &args) {
2847 
2848  std::string positional = args.back();
2849  for(const Option_p &opt : options_) {
2850  // Eat options, one by one, until done
2851  if(opt->get_positional() &&
2852  (static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) {
2853 
2854  opt->add_result(positional);
2855  parse_order_.push_back(opt.get());
2856  args.pop_back();
2857  return;
2858  }
2859  }
2860 
2861  if(parent_ != nullptr && fallthrough_)
2862  return parent_->_parse_positional(args);
2863  else {
2864  args.pop_back();
2865  missing_.emplace_back(detail::Classifer::NONE, positional);
2866 
2867  if(prefix_command_) {
2868  while(!args.empty()) {
2869  missing_.emplace_back(detail::Classifer::NONE, args.back());
2870  args.pop_back();
2871  }
2872  }
2873  }
2874  }
2875 
2879  void _parse_subcommand(std::vector<std::string> &args) {
2880  if(_count_remaining_positionals(/* required */ true) > 0)
2881  return _parse_positional(args);
2882  for(const App_p &com : subcommands_) {
2883  if(com->check_name(args.back())) {
2884  args.pop_back();
2885  if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com.get()) ==
2886  std::end(parsed_subcommands_))
2887  parsed_subcommands_.push_back(com.get());
2888  com->_parse(args);
2889  return;
2890  }
2891  }
2892  if(parent_ != nullptr)
2893  return parent_->_parse_subcommand(args);
2894  else
2895  throw HorribleError("Subcommand " + args.back() + " missing");
2896  }
2897 
2899  void _parse_arg(std::vector<std::string> &args, bool second_dash) {
2900 
2901  detail::Classifer current_type = second_dash ? detail::Classifer::LONG : detail::Classifer::SHORT;
2902 
2903  std::string current = args.back();
2904 
2905  std::string name;
2906  std::string value;
2907  std::string rest;
2908 
2909  if(second_dash) {
2910  if(!detail::split_long(current, name, value))
2911  throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
2912  } else {
2913  if(!detail::split_short(current, name, rest))
2914  throw HorribleError("Short parsed but missing! You should not see this");
2915  }
2916 
2917  auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [name, second_dash](const Option_p &opt) {
2918  return second_dash ? opt->check_lname(name) : opt->check_sname(name);
2919  });
2920 
2921  // Option not found
2922  if(op_ptr == std::end(options_)) {
2923  // If a subcommand, try the master command
2924  if(parent_ != nullptr && fallthrough_)
2925  return parent_->_parse_arg(args, second_dash);
2926  // Otherwise, add to missing
2927  else {
2928  args.pop_back();
2929  missing_.emplace_back(current_type, current);
2930  return;
2931  }
2932  }
2933 
2934  args.pop_back();
2935 
2936  // Get a reference to the pointer to make syntax bearable
2937  Option_p &op = *op_ptr;
2938 
2939  int num = op->get_expected();
2940 
2941  if(!value.empty()) {
2942  if(num != -1)
2943  num--;
2944  op->add_result(value);
2945  parse_order_.push_back(op.get());
2946  } else if(num == 0) {
2947  op->add_result("");
2948  parse_order_.push_back(op.get());
2949  } else if(!rest.empty()) {
2950  if(num > 0)
2951  num--;
2952  op->add_result(rest);
2953  parse_order_.push_back(op.get());
2954  rest = "";
2955  }
2956 
2957  // Unlimited vector parser
2958  if(num < 0) {
2959  int collected = 0; // Make sure we always eat the minimum
2960  while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {
2961  if(collected >= -num) {
2962  // We could break here for allow extras, but we don't
2963 
2964  // If any positionals remain, don't keep eating
2965  if(_count_remaining_positionals() > 0)
2966  break;
2967 
2968  // If there are any unlimited positionals, those also take priority
2969  if(std::any_of(std::begin(options_), std::end(options_), [](const Option_p &opt) {
2970  return opt->get_positional() && opt->get_expected() < 0;
2971  }))
2972  break;
2973  }
2974  op->add_result(args.back());
2975  parse_order_.push_back(op.get());
2976  args.pop_back();
2977  collected++;
2978  }
2979 
2980  } else {
2981  while(num > 0 && !args.empty()) {
2982  num--;
2983  std::string current_ = args.back();
2984  args.pop_back();
2985  op->add_result(current_);
2986  parse_order_.push_back(op.get());
2987  }
2988 
2989  if(num > 0) {
2990  throw ArgumentMismatch::TypedAtLeast(op->single_name(), num, op->get_type_name());
2991  }
2992  }
2993 
2994  if(!rest.empty()) {
2995  rest = "-" + rest;
2996  args.push_back(rest);
2997  }
2998  }
2999 };
3000 
3001 namespace FailureMessage {
3002 
3003 inline std::string simple(const App *app, const Error &e) {
3004  std::string header = std::string(e.what()) + "\n";
3005  if(app->get_help_ptr() != nullptr)
3006  header += "Run with " + app->get_help_ptr()->single_name() + " for more information.\n";
3007  return header;
3008 }
3009 
3010 inline std::string help(const App *app, const Error &e) {
3011  std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
3012  header += app->help();
3013  return header;
3014 }
3015 
3016 } // namespace FailureMessage
3017 
3018 namespace detail {
3020 struct AppFriend {
3021 
3023  template <typename... Args>
3024  static auto parse_arg(App *app, Args &&... args) ->
3025  typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>::type {
3026  return app->_parse_arg(std::forward<Args>(args)...);
3027  }
3028 
3030  template <typename... Args>
3031  static auto parse_subcommand(App *app, Args &&... args) ->
3032  typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
3033  return app->_parse_subcommand(std::forward<Args>(args)...);
3034  }
3035 };
3036 } // namespace detail
3037 
3038 } // namespace CLI
Definition: CL11.hpp:35
All errors derive from this one.
Definition: CL11.hpp:293
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: CL11.hpp:171
#define CLI11_ERROR_SIMPLE(name)
Definition: CL11.hpp:259
-h or –help on command line
Definition: CL11.hpp:383
Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error c...
Definition: CL11.hpp:389
std::string & ltrim(std::string &str)
Trim whitespace from left of string.
Definition: CL11.hpp:95
bool lexical_cast(std::string input, T &output)
Signed integers / enums.
Definition: CL11.hpp:587
Definition: CL11.hpp:500
std::vector< std::string > split_up(std::string str)
Split a string &#39;"one two" "three"&#39; into &#39;one two&#39;, &#39;three&#39;.
Definition: CL11.hpp:179
bool split_short(const std::string &current, std::string &name, std::string &rest)
Definition: CL11.hpp:672
Thrown when an excludes option is present.
Definition: CL11.hpp:464
Error(std::string name, std::string msg, int exit_code=static_cast< int >(ExitCodes::BaseClass))
Definition: CL11.hpp:302
#define CLI11_ERROR_DEF(parent, name)
Definition: CL11.hpp:248
std::string trim_copy(const std::string &str)
Make a copy of the string and then trim it.
Definition: CL11.hpp:130
size_t count(const std::string &str, const std::string &sub)
Definition: Strings.h:344
bool split_long(const std::string &current, std::string &name, std::string &value)
Definition: CL11.hpp:682
std::string reverse(std::string x)
Definition: Strings.h:376
constexpr const char * type_name()
This one should not be used, since vector types print the internal type.
Definition: CL11.hpp:553
Definition: CL11.hpp:529
std::string rjoin(const T &v, std::string delim=",")
Join a string in reverse order.
Definition: CL11.hpp:82
Thrown when an option is set to conflicting values (non-vector and multi args, for example) ...
Definition: CL11.hpp:316
Thrown when extra values are found in an INI file.
Definition: CL11.hpp:481
std::string str(BindingTree *t)
Definition: BindingTree.h:183
std::string get_name() const
Definition: CL11.hpp:300
Thrown when too many positionals or options are found.
Definition: CL11.hpp:471
std::vector< std::string > split_names(std::string current)
Definition: CL11.hpp:698
bool valid_later_char(T c)
Verify following characters of an option.
Definition: CL11.hpp:156
bool valid_name_string(const std::string &str)
Verify an option name.
Definition: CL11.hpp:161
typename std::enable_if< B, T >::type enable_if_t
Definition: CL11.hpp:527
std::string & rtrim(std::string &str)
Trim whitespace from right of string.
Definition: CL11.hpp:109
bool valid_first_char(T c)
Verify the first character of an option.
Definition: CL11.hpp:153
std::tuple< std::vector< std::string >, std::vector< std::string >, std::string > get_names(const std::vector< std::string > &input)
Get a vector of short names, one of long names, and a single name.
Definition: CL11.hpp:711
Thrown when a requires option is missing.
Definition: CL11.hpp:457
Thrown when validation fails before parsing.
Definition: CL11.hpp:491
ExitCodes
Definition: CL11.hpp:264
Thrown when parsing an INI file and it is missing.
Definition: CL11.hpp:395
Error(std::string name, std::string msg, ExitCodes exit_code)
Definition: CL11.hpp:305
Definition: CL11.hpp:533
int get_exit_code() const
Definition: CL11.hpp:298
Construction errors (not in parsing)
Definition: CL11.hpp:311
Thrown when an option already exists.
Definition: CL11.hpp:355
Thrown when counting a non-existent option.
Definition: CL11.hpp:508
enabler
Simple empty scoped class.
Definition: CL11.hpp:540
This is a successful completion on parsing, supposed to exit.
Definition: CL11.hpp:377
std::string fix_newlines(std::string leader, std::string input)
Definition: CL11.hpp:228
Thrown on construction of a bad name.
Definition: CL11.hpp:341
void reset()
Definition: FleetStatistics.h:20
Anything that can error in Parse.
Definition: CL11.hpp:370
Thrown when the wrong number of arguments has been received.
Definition: CL11.hpp:438
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition: CL11.hpp:402
std::vector< std::string > split(const std::string &s, char delim)
Split a string by a delim.
Definition: CL11.hpp:53
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: CL11.hpp:124
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: CL11.hpp:70
Thrown when a required option is missing.
Definition: CL11.hpp:425
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CL11.hpp:543
T parse(std::vector< std::string > &tok)
Definition: SExpression.h:63
void format_help(std::stringstream &out, std::string name, std::string description, size_t wid)
Print a two part "help" string.
Definition: CL11.hpp:141
Thrown when validation of results fails.
Definition: CL11.hpp:418