mlpack
CLI11.hpp
1 // CLI11: Version 2.0.0
2 // Originally designed by Henry Schreiner
3 // https://github.com/CLIUtils/CLI11
4 //
5 // This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
6 // from: v2.0.0 (added include gaurd)
7 //
8 // CLI11 2.0.0 Copyright (c) 2017-2020 University of Cincinnati, developed by Henry
9 // Schreiner under NSF AWARD 1414736. All rights reserved.
10 //
11 // Redistribution and use in source and binary forms of CLI11, with or without
12 // modification, are permitted provided that the following conditions are met:
13 //
14 // 1. Redistributions of source code must retain the above copyright notice, this
15 // list of conditions and the following disclaimer.
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 // 3. Neither the name of the copyright holder nor the names of its contributors
20 // may be used to endorse or promote products derived from this software without
21 // specific prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 #pragma once
35 
36 // Standard combined includes:
37 #include <memory>
38 #include <string>
39 #include <functional>
40 #include <vector>
41 #include <exception>
42 #include <sstream>
43 #include <cstdint>
44 #include <utility>
45 #include <iomanip>
46 #include <iterator>
47 #include <algorithm>
48 #include <tuple>
49 #include <stdexcept>
50 #include <iostream>
51 #include <fstream>
52 #include <locale>
53 #include <type_traits>
54 #include <map>
55 #include <limits>
56 #include <numeric>
57 #include <cmath>
58 #include <set>
59 
60 
61 #define CLI11_VERSION_MAJOR 2
62 #define CLI11_VERSION_MINOR 0
63 #define CLI11_VERSION_PATCH 0
64 #define CLI11_VERSION "2.0.0"
65 
66 
67 
68 
69 // The following version macro is very similar to the one in pybind11
70 #if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
71 #if __cplusplus >= 201402L
72 #define CLI11_CPP14
73 #if __cplusplus >= 201703L
74 #define CLI11_CPP17
75 #if __cplusplus > 201703L
76 #define CLI11_CPP20
77 #endif
78 #endif
79 #endif
80 #elif defined(_MSC_VER) && __cplusplus == 199711L
81 // MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented)
82 // Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer
83 #if _MSVC_LANG >= 201402L
84 #define CLI11_CPP14
85 #if _MSVC_LANG > 201402L && _MSC_VER >= 1910
86 #define CLI11_CPP17
87 #if __MSVC_LANG > 201703L && _MSC_VER >= 1910
88 #define CLI11_CPP20
89 #endif
90 #endif
91 #endif
92 #endif
93 
94 #if defined(CLI11_CPP14)
95 #define CLI11_DEPRECATED(reason) [[deprecated(reason)]]
96 #elif defined(_MSC_VER)
97 #define CLI11_DEPRECATED(reason) __declspec(deprecated(reason))
98 #else
99 #define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason)))
100 #endif
101 
102 
103 
104 
105 // C standard library
106 // Only needed for existence checking
107 #if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
108 #if __has_include(<filesystem>)
109 // Filesystem cannot be used if targeting macOS < 10.15
110 #if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
111 #define CLI11_HAS_FILESYSTEM 0
112 #else
113 #include <filesystem>
114 #if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
115 #if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
116 #define CLI11_HAS_FILESYSTEM 1
117 #elif defined(__GLIBCXX__)
118 // if we are using gcc and Version <9 default to no filesystem
119 #define CLI11_HAS_FILESYSTEM 0
120 #else
121 #define CLI11_HAS_FILESYSTEM 1
122 #endif
123 #else
124 #define CLI11_HAS_FILESYSTEM 0
125 #endif
126 #endif
127 #endif
128 #endif
129 
130 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
131 #include <filesystem> // NOLINT(build/include)
132 #else
133 #include <sys/stat.h>
134 #include <sys/types.h>
135 #endif
136 
137 
138 
139 namespace CLI {
140 
141 
144 namespace enums {
145 
147 template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
148 std::ostream &operator<<(std::ostream &in, const T &item) {
149  // make sure this is out of the detail namespace otherwise it won't be found when needed
150  return in << static_cast<typename std::underlying_type<T>::type>(item);
151 }
152 
153 } // namespace enums
154 
156 using enums::operator<<;
157 
158 namespace detail {
161 constexpr int expected_max_vector_size{1 << 29};
162 // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
164 inline std::vector<std::string> split(const std::string &s, char delim) {
165  std::vector<std::string> elems;
166  // Check to see if empty string, give consistent result
167  if(s.empty()) {
168  elems.emplace_back();
169  } else {
170  std::stringstream ss;
171  ss.str(s);
172  std::string item;
173  while(std::getline(ss, item, delim)) {
174  elems.push_back(item);
175  }
176  }
177  return elems;
178 }
179 
181 template <typename T> std::string join(const T &v, std::string delim = ",") {
182  std::ostringstream s;
183  auto beg = std::begin(v);
184  auto end = std::end(v);
185  if(beg != end)
186  s << *beg++;
187  while(beg != end) {
188  s << delim << *beg++;
189  }
190  return s.str();
191 }
192 
194 template <typename T,
195  typename Callable,
196  typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
197 std::string join(const T &v, Callable func, std::string delim = ",") {
198  std::ostringstream s;
199  auto beg = std::begin(v);
200  auto end = std::end(v);
201  auto loc = s.tellp();
202  while(beg != end) {
203  auto nloc = s.tellp();
204  if(nloc > loc) {
205  s << delim;
206  loc = nloc;
207  }
208  s << func(*beg++);
209  }
210  return s.str();
211 }
212 
214 template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
215  std::ostringstream s;
216  for(std::size_t start = 0; start < v.size(); start++) {
217  if(start > 0)
218  s << delim;
219  s << v[v.size() - start - 1];
220  }
221  return s.str();
222 }
223 
224 // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
225 
227 inline std::string &ltrim(std::string &str) {
228  auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
229  str.erase(str.begin(), it);
230  return str;
231 }
232 
234 inline std::string &ltrim(std::string &str, const std::string &filter) {
235  auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
236  str.erase(str.begin(), it);
237  return str;
238 }
239 
241 inline std::string &rtrim(std::string &str) {
242  auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
243  str.erase(it.base(), str.end());
244  return str;
245 }
246 
248 inline std::string &rtrim(std::string &str, const std::string &filter) {
249  auto it =
250  std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
251  str.erase(it.base(), str.end());
252  return str;
253 }
254 
256 inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
257 
259 inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); }
260 
262 inline std::string trim_copy(const std::string &str) {
263  std::string s = str;
264  return trim(s);
265 }
266 
268 inline std::string &remove_quotes(std::string &str) {
269  if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) {
270  if(str.front() == str.back()) {
271  str.pop_back();
272  str.erase(str.begin(), str.begin() + 1);
273  }
274  }
275  return str;
276 }
277 
279 inline std::string trim_copy(const std::string &str, const std::string &filter) {
280  std::string s = str;
281  return trim(s, filter);
282 }
284 inline std::ostream &format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) {
285  name = " " + name;
286  out << std::setw(static_cast<int>(wid)) << std::left << name;
287  if(!description.empty()) {
288  if(name.length() >= wid)
289  out << "\n" << std::setw(static_cast<int>(wid)) << "";
290  for(const char c : description) {
291  out.put(c);
292  if(c == '\n') {
293  out << std::setw(static_cast<int>(wid)) << "";
294  }
295  }
296  }
297  out << "\n";
298  return out;
299 }
300 
302 inline std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) {
303  if(!aliases.empty()) {
304  out << std::setw(static_cast<int>(wid)) << " aliases: ";
305  bool front = true;
306  for(const auto &alias : aliases) {
307  if(!front) {
308  out << ", ";
309  } else {
310  front = false;
311  }
312  out << alias;
313  }
314  out << "\n";
315  }
316  return out;
317 }
318 
320 template <typename T> bool valid_first_char(T c) {
321  return std::isalnum(c, std::locale()) || c == '_' || c == '?' || c == '@';
322 }
323 
325 template <typename T> bool valid_later_char(T c) { return valid_first_char(c) || c == '.' || c == '-'; }
326 
328 inline bool valid_name_string(const std::string &str) {
329  if(str.empty() || !valid_first_char(str[0]))
330  return false;
331  for(auto c : str.substr(1))
332  if(!valid_later_char(c))
333  return false;
334  return true;
335 }
336 
338 inline bool is_separator(const std::string &str) {
339  static const std::string sep("%%");
340  return (str.empty() || str == sep);
341 }
342 
344 inline bool isalpha(const std::string &str) {
345  return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); });
346 }
347 
349 inline std::string to_lower(std::string str) {
350  std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) {
351  return std::tolower(x, std::locale());
352  });
353  return str;
354 }
355 
357 inline std::string remove_underscore(std::string str) {
358  str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str));
359  return str;
360 }
361 
363 inline std::string find_and_replace(std::string str, std::string from, std::string to) {
364 
365  std::size_t start_pos = 0;
366 
367  while((start_pos = str.find(from, start_pos)) != std::string::npos) {
368  str.replace(start_pos, from.length(), to);
369  start_pos += to.length();
370  }
371 
372  return str;
373 }
374 
376 inline bool has_default_flag_values(const std::string &flags) {
377  return (flags.find_first_of("{!") != std::string::npos);
378 }
379 
380 inline void remove_default_flag_values(std::string &flags) {
381  auto loc = flags.find_first_of('{');
382  while(loc != std::string::npos) {
383  auto finish = flags.find_first_of("},", loc + 1);
384  if((finish != std::string::npos) && (flags[finish] == '}')) {
385  flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
386  flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
387  }
388  loc = flags.find_first_of('{', loc + 1);
389  }
390  flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end());
391 }
392 
394 inline std::ptrdiff_t find_member(std::string name,
395  const std::vector<std::string> names,
396  bool ignore_case = false,
397  bool ignore_underscore = false) {
398  auto it = std::end(names);
399  if(ignore_case) {
400  if(ignore_underscore) {
401  name = detail::to_lower(detail::remove_underscore(name));
402  it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
403  return detail::to_lower(detail::remove_underscore(local_name)) == name;
404  });
405  } else {
406  name = detail::to_lower(name);
407  it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
408  return detail::to_lower(local_name) == name;
409  });
410  }
411 
412  } else if(ignore_underscore) {
413  name = detail::remove_underscore(name);
414  it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
415  return detail::remove_underscore(local_name) == name;
416  });
417  } else {
418  it = std::find(std::begin(names), std::end(names), name);
419  }
420 
421  return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
422 }
423 
426 template <typename Callable> inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
427  std::size_t start_pos = 0;
428  while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
429  start_pos = modify(str, start_pos);
430  }
431  return str;
432 }
433 
436 inline std::vector<std::string> split_up(std::string str, char delimiter = '\0') {
437 
438  const std::string delims("\'\"`");
439  auto find_ws = [delimiter](char ch) {
440  return (delimiter == '\0') ? (std::isspace<char>(ch, std::locale()) != 0) : (ch == delimiter);
441  };
442  trim(str);
443 
444  std::vector<std::string> output;
445  bool embeddedQuote = false;
446  char keyChar = ' ';
447  while(!str.empty()) {
448  if(delims.find_first_of(str[0]) != std::string::npos) {
449  keyChar = str[0];
450  auto end = str.find_first_of(keyChar, 1);
451  while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes
452  end = str.find_first_of(keyChar, end + 1);
453  embeddedQuote = true;
454  }
455  if(end != std::string::npos) {
456  output.push_back(str.substr(1, end - 1));
457  if(end + 2 < str.size()) {
458  str = str.substr(end + 2);
459  } else {
460  str.clear();
461  }
462 
463  } else {
464  output.push_back(str.substr(1));
465  str = "";
466  }
467  } else {
468  auto it = std::find_if(std::begin(str), std::end(str), find_ws);
469  if(it != std::end(str)) {
470  std::string value = std::string(str.begin(), it);
471  output.push_back(value);
472  str = std::string(it + 1, str.end());
473  } else {
474  output.push_back(str);
475  str = "";
476  }
477  }
478  // transform any embedded quotes into the regular character
479  if(embeddedQuote) {
480  output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar));
481  embeddedQuote = false;
482  }
483  trim(str);
484  }
485  return output;
486 }
487 
492 inline std::string fix_newlines(const std::string &leader, std::string input) {
493  std::string::size_type n = 0;
494  while(n != std::string::npos && n < input.size()) {
495  n = input.find('\n', n);
496  if(n != std::string::npos) {
497  input = input.substr(0, n + 1) + leader + input.substr(n + 1);
498  n += leader.size();
499  }
500  }
501  return input;
502 }
503 
508 inline std::size_t escape_detect(std::string &str, std::size_t offset) {
509  auto next = str[offset + 1];
510  if((next == '\"') || (next == '\'') || (next == '`')) {
511  auto astart = str.find_last_of("-/ \"\'`", offset - 1);
512  if(astart != std::string::npos) {
513  if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
514  str[offset] = ' '; // interpret this as a space so the split_up works properly
515  }
516  }
517  return offset + 1;
518 }
519 
521 inline std::string &add_quotes_if_needed(std::string &str) {
522  if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) {
523  char quote = str.find('"') < str.find('\'') ? '\'' : '"';
524  if(str.find(' ') != std::string::npos) {
525  str.insert(0, 1, quote);
526  str.append(1, quote);
527  }
528  }
529  return str;
530 }
531 
532 } // namespace detail
533 
534 
535 
536 
537 // Use one of these on all error classes.
538 // These are temporary and are undef'd at the end of this file.
539 #define CLI11_ERROR_DEF(parent, name) \
540  protected: \
541  name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
542  name(std::string ename, std::string msg, ExitCodes exit_code) \
543  : parent(std::move(ename), std::move(msg), exit_code) {} \
544  \
545  public: \
546  name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
547  name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
548 
549 // This is added after the one above if a class is used directly and builds its own message
550 #define CLI11_ERROR_SIMPLE(name) \
551  explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
552 
555 enum class ExitCodes {
556  Success = 0,
557  IncorrectConstruction = 100,
560  FileError,
566  ExtrasError,
567  ConfigError,
568  InvalidError,
572  BaseClass = 127
573 };
574 
575 // Error definitions
576 
582 
584 class Error : public std::runtime_error {
585  int actual_exit_code;
586  std::string error_name{"Error"};
587 
588  public:
589  int get_exit_code() const { return actual_exit_code; }
590 
591  std::string get_name() const { return error_name; }
592 
593  Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
594  : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
595 
596  Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
597 };
598 
599 // Note: Using Error::Error constructors does not work on GCC 4.7
600 
602 class ConstructionError : public Error {
603  CLI11_ERROR_DEF(Error, ConstructionError)
604 };
605 
608  CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction)
609  CLI11_ERROR_SIMPLE(IncorrectConstruction)
610  static IncorrectConstruction PositionalFlag(std::string name) {
611  return IncorrectConstruction(name + ": Flags cannot be positional");
612  }
613  static IncorrectConstruction Set0Opt(std::string name) {
614  return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
615  }
616  static IncorrectConstruction SetFlag(std::string name) {
617  return IncorrectConstruction(name + ": Cannot set an expected number for flags");
618  }
619  static IncorrectConstruction ChangeNotVector(std::string name) {
620  return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
621  }
622  static IncorrectConstruction AfterMultiOpt(std::string name) {
623  return IncorrectConstruction(
624  name + ": You can't change expected arguments after you've changed the multi option policy!");
625  }
626  static IncorrectConstruction MissingOption(std::string name) {
627  return IncorrectConstruction("Option " + name + " is not defined");
628  }
629  static IncorrectConstruction MultiOptionPolicy(std::string name) {
630  return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options");
631  }
632 };
633 
636  CLI11_ERROR_DEF(ConstructionError, BadNameString)
637  CLI11_ERROR_SIMPLE(BadNameString)
638  static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); }
639  static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
640  static BadNameString DashesOnly(std::string name) {
641  return BadNameString("Must have a name, not just dashes: " + name);
642  }
643  static BadNameString MultiPositionalNames(std::string name) {
644  return BadNameString("Only one positional name allowed, remove: " + name);
645  }
646 };
647 
650  CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded)
651  explicit OptionAlreadyAdded(std::string name)
652  : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {}
653  static OptionAlreadyAdded Requires(std::string name, std::string other) {
654  return OptionAlreadyAdded(name + " requires " + other, ExitCodes::OptionAlreadyAdded);
655  }
656  static OptionAlreadyAdded Excludes(std::string name, std::string other) {
657  return OptionAlreadyAdded(name + " excludes " + other, ExitCodes::OptionAlreadyAdded);
658  }
659 };
660 
661 // Parsing errors
662 
664 class ParseError : public Error {
665  CLI11_ERROR_DEF(Error, ParseError)
666 };
667 
668 // Not really "errors"
669 
671 class Success : public ParseError {
672  CLI11_ERROR_DEF(ParseError, Success)
673  Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
674 };
675 
677 class CallForHelp : public Success {
678  CLI11_ERROR_DEF(Success, CallForHelp)
679  CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
680 };
681 
683 class CallForAllHelp : public Success {
684  CLI11_ERROR_DEF(Success, CallForAllHelp)
686  : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
687 };
688 
690 class CallForVersion : public Success {
691  CLI11_ERROR_DEF(Success, CallForVersion)
693  : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {}
694 };
695 
697 class RuntimeError : public ParseError {
698  CLI11_ERROR_DEF(ParseError, RuntimeError)
699  explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
700 };
701 
703 class FileError : public ParseError {
704  CLI11_ERROR_DEF(ParseError, FileError)
705  CLI11_ERROR_SIMPLE(FileError)
706  static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); }
707 };
708 
710 class ConversionError : public ParseError {
711  CLI11_ERROR_DEF(ParseError, ConversionError)
712  CLI11_ERROR_SIMPLE(ConversionError)
713  ConversionError(std::string member, std::string name)
714  : ConversionError("The value " + member + " is not an allowed value for " + name) {}
715  ConversionError(std::string name, std::vector<std::string> results)
716  : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
717  static ConversionError TooManyInputsFlag(std::string name) {
718  return ConversionError(name + ": too many inputs for a flag");
719  }
720  static ConversionError TrueFalse(std::string name) {
721  return ConversionError(name + ": Should be true/false or a number");
722  }
723 };
724 
726 class ValidationError : public ParseError {
727  CLI11_ERROR_DEF(ParseError, ValidationError)
728  CLI11_ERROR_SIMPLE(ValidationError)
729  explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {}
730 };
731 
733 class RequiredError : public ParseError {
734  CLI11_ERROR_DEF(ParseError, RequiredError)
735  explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
736  static RequiredError Subcommand(std::size_t min_subcom) {
737  if(min_subcom == 1) {
738  return RequiredError("A subcommand");
739  }
740  return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands",
741  ExitCodes::RequiredError);
742  }
743  static RequiredError
744  Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) {
745  if((min_option == 1) && (max_option == 1) && (used == 0))
746  return RequiredError("Exactly 1 option from [" + option_list + "]");
747  if((min_option == 1) && (max_option == 1) && (used > 1)) {
748  return RequiredError("Exactly 1 option from [" + option_list + "] is required and " + std::to_string(used) +
749  " were given",
750  ExitCodes::RequiredError);
751  }
752  if((min_option == 1) && (used == 0))
753  return RequiredError("At least 1 option from [" + option_list + "]");
754  if(used < min_option) {
755  return RequiredError("Requires at least " + std::to_string(min_option) + " options used and only " +
756  std::to_string(used) + "were given from [" + option_list + "]",
757  ExitCodes::RequiredError);
758  }
759  if(max_option == 1)
760  return RequiredError("Requires at most 1 options be given from [" + option_list + "]",
761  ExitCodes::RequiredError);
762 
763  return RequiredError("Requires at most " + std::to_string(max_option) + " options be used and " +
764  std::to_string(used) + "were given from [" + option_list + "]",
765  ExitCodes::RequiredError);
766  }
767 };
768 
770 class ArgumentMismatch : public ParseError {
771  CLI11_ERROR_DEF(ParseError, ArgumentMismatch)
772  CLI11_ERROR_SIMPLE(ArgumentMismatch)
773  ArgumentMismatch(std::string name, int expected, std::size_t received)
774  : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
775  ", got " + std::to_string(received))
776  : ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
777  ", got " + std::to_string(received)),
778  ExitCodes::ArgumentMismatch) {}
779 
780  static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) {
781  return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " +
782  std::to_string(received));
783  }
784  static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) {
785  return ArgumentMismatch(name + ": At Most " + std::to_string(num) + " required but received " +
786  std::to_string(received));
787  }
788  static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) {
789  return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");
790  }
791  static ArgumentMismatch FlagOverride(std::string name) {
792  return ArgumentMismatch(name + " was given a disallowed flag override");
793  }
794 };
795 
797 class RequiresError : public ParseError {
798  CLI11_ERROR_DEF(ParseError, RequiresError)
799  RequiresError(std::string curname, std::string subname)
800  : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
801 };
802 
804 class ExcludesError : public ParseError {
805  CLI11_ERROR_DEF(ParseError, ExcludesError)
806  ExcludesError(std::string curname, std::string subname)
807  : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
808 };
809 
811 class ExtrasError : public ParseError {
812  CLI11_ERROR_DEF(ParseError, ExtrasError)
813  explicit ExtrasError(std::vector<std::string> args)
814  : ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
815  : "The following argument was not expected: ") +
816  detail::rjoin(args, " "),
817  ExitCodes::ExtrasError) {}
818  ExtrasError(const std::string &name, std::vector<std::string> args)
819  : ExtrasError(name,
820  (args.size() > 1 ? "The following arguments were not expected: "
821  : "The following argument was not expected: ") +
822  detail::rjoin(args, " "),
823  ExitCodes::ExtrasError) {}
824 };
825 
827 class ConfigError : public ParseError {
828  CLI11_ERROR_DEF(ParseError, ConfigError)
829  CLI11_ERROR_SIMPLE(ConfigError)
830  static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); }
831  static ConfigError NotConfigurable(std::string item) {
832  return ConfigError(item + ": This option is not allowed in a configuration file");
833  }
834 };
835 
837 class InvalidError : public ParseError {
838  CLI11_ERROR_DEF(ParseError, InvalidError)
839  explicit InvalidError(std::string name)
840  : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
841  }
842 };
843 
846 class HorribleError : public ParseError {
847  CLI11_ERROR_DEF(ParseError, HorribleError)
848  CLI11_ERROR_SIMPLE(HorribleError)
849 };
850 
851 // After parsing
852 
854 class OptionNotFound : public Error {
855  CLI11_ERROR_DEF(Error, OptionNotFound)
856  explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {}
857 };
858 
859 #undef CLI11_ERROR_DEF
860 #undef CLI11_ERROR_SIMPLE
861 
863 
864 
865 
866 
867 // Type tools
868 
869 // Utilities for type enabling
870 namespace detail {
871 // Based generally on https://rmf.io/cxx11/almost-static-if
873 enum class enabler {};
874 
876 constexpr enabler dummy = {};
877 } // namespace detail
878 
884 template <bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
885 
887 template <typename... Ts> struct make_void { using type = void; };
888 
890 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
891 
893 template <bool B, class T, class F> using conditional_t = typename std::conditional<B, T, F>::type;
894 
896 template <typename T> struct is_bool : std::false_type {};
897 
899 template <> struct is_bool<bool> : std::true_type {};
900 
902 template <typename T> struct is_shared_ptr : std::false_type {};
903 
905 template <typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
906 
908 template <typename T> struct is_shared_ptr<const std::shared_ptr<T>> : std::true_type {};
909 
911 template <typename T> struct is_copyable_ptr {
912  static bool const value = is_shared_ptr<T>::value || std::is_pointer<T>::value;
913 };
914 
916 template <typename T> struct IsMemberType { using type = T; };
917 
919 template <> struct IsMemberType<const char *> { using type = std::string; };
920 
921 namespace detail {
922 
923 // These are utilities for IsMember and other transforming objects
924 
927 
929 template <typename T, typename Enable = void> struct element_type { using type = T; };
930 
931 template <typename T> struct element_type<T, typename std::enable_if<is_copyable_ptr<T>::value>::type> {
932  using type = typename std::pointer_traits<T>::element_type;
933 };
934 
937 template <typename T> struct element_value_type { using type = typename element_type<T>::type::value_type; };
938 
940 template <typename T, typename _ = void> struct pair_adaptor : std::false_type {
941  using value_type = typename T::value_type;
942  using first_type = typename std::remove_const<value_type>::type;
943  using second_type = typename std::remove_const<value_type>::type;
944 
946  template <typename Q> static auto first(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
947  return std::forward<Q>(pair_value);
948  }
950  template <typename Q> static auto second(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
951  return std::forward<Q>(pair_value);
952  }
953 };
954 
957 template <typename T>
959  T,
960  conditional_t<false, void_t<typename T::value_type::first_type, typename T::value_type::second_type>, void>>
961  : std::true_type {
962  using value_type = typename T::value_type;
963  using first_type = typename std::remove_const<typename value_type::first_type>::type;
964  using second_type = typename std::remove_const<typename value_type::second_type>::type;
965 
967  template <typename Q> static auto first(Q &&pair_value) -> decltype(std::get<0>(std::forward<Q>(pair_value))) {
968  return std::get<0>(std::forward<Q>(pair_value));
969  }
971  template <typename Q> static auto second(Q &&pair_value) -> decltype(std::get<1>(std::forward<Q>(pair_value))) {
972  return std::get<1>(std::forward<Q>(pair_value));
973  }
974 };
975 
976 // Warning is suppressed due to "bug" in gcc<5.0 and gcc 7.0 with c++17 enabled that generates a Wnarrowing warning
977 // in the unevaluated context even if the function that was using this wasn't used. The standard says narrowing in
978 // brace initialization shouldn't be allowed but for backwards compatibility gcc allows it in some contexts. It is a
979 // little fuzzy what happens in template constructs and I think that was something GCC took a little while to work out.
980 // But regardless some versions of gcc generate a warning when they shouldn't from the following code so that should be
981 // suppressed
982 #ifdef __GNUC__
983 #pragma GCC diagnostic push
984 #pragma GCC diagnostic ignored "-Wnarrowing"
985 #endif
986 // check for constructibility from a specific type and copy assignable used in the parse detection
987 template <typename T, typename C> class is_direct_constructible {
988  template <typename TT, typename CC>
989  static auto test(int, std::true_type) -> decltype(
990 // NVCC warns about narrowing conversions here
991 #ifdef __CUDACC__
992 #pragma diag_suppress 2361
993 #endif
994  TT { std::declval<CC>() }
995 #ifdef __CUDACC__
996 #pragma diag_default 2361
997 #endif
998  ,
999  std::is_move_assignable<TT>());
1000 
1001  template <typename TT, typename CC> static auto test(int, std::false_type) -> std::false_type;
1002 
1003  template <typename, typename> static auto test(...) -> std::false_type;
1004 
1005  public:
1006  static constexpr bool value = decltype(test<T, C>(0, typename std::is_constructible<T, C>::type()))::value;
1007 };
1008 #ifdef __GNUC__
1009 #pragma GCC diagnostic pop
1010 #endif
1011 
1012 // Check for output streamability
1013 // Based on https://stackoverflow.com/questions/22758291/how-can-i-detect-if-a-type-can-be-streamed-to-an-stdostream
1014 
1015 template <typename T, typename S = std::ostringstream> class is_ostreamable {
1016  template <typename TT, typename SS>
1017  static auto test(int) -> decltype(std::declval<SS &>() << std::declval<TT>(), std::true_type());
1018 
1019  template <typename, typename> static auto test(...) -> std::false_type;
1020 
1021  public:
1022  static constexpr bool value = decltype(test<T, S>(0))::value;
1023 };
1024 
1026 template <typename T, typename S = std::istringstream> class is_istreamable {
1027  template <typename TT, typename SS>
1028  static auto test(int) -> decltype(std::declval<SS &>() >> std::declval<TT &>(), std::true_type());
1029 
1030  template <typename, typename> static auto test(...) -> std::false_type;
1031 
1032  public:
1033  static constexpr bool value = decltype(test<T, S>(0))::value;
1034 };
1035 
1037 template <typename T> class is_complex {
1038  template <typename TT>
1039  static auto test(int) -> decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());
1040 
1041  template <typename> static auto test(...) -> std::false_type;
1042 
1043  public:
1044  static constexpr bool value = decltype(test<T>(0))::value;
1045 };
1046 
1048 template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
1049 bool from_stream(const std::string &istring, T &obj) {
1050  std::istringstream is;
1051  is.str(istring);
1052  is >> obj;
1053  return !is.fail() && !is.rdbuf()->in_avail();
1054 }
1055 
1056 template <typename T, enable_if_t<!is_istreamable<T>::value, detail::enabler> = detail::dummy>
1057 bool from_stream(const std::string & /*istring*/, T & /*obj*/) {
1058  return false;
1059 }
1060 
1061 // check to see if an object is a mutable container (fail by default)
1062 template <typename T, typename _ = void> struct is_mutable_container : std::false_type {};
1063 
1067 template <typename T>
1069  T,
1070  conditional_t<false,
1071  void_t<typename T::value_type,
1072  decltype(std::declval<T>().end()),
1073  decltype(std::declval<T>().clear()),
1074  decltype(std::declval<T>().insert(std::declval<decltype(std::declval<T>().end())>(),
1075  std::declval<const typename T::value_type &>()))>,
1076  void>>
1077  : public conditional_t<std::is_constructible<T, std::string>::value, std::false_type, std::true_type> {};
1078 
1079 // check to see if an object is a mutable container (fail by default)
1080 template <typename T, typename _ = void> struct is_readable_container : std::false_type {};
1081 
1085 template <typename T>
1087  T,
1088  conditional_t<false, void_t<decltype(std::declval<T>().end()), decltype(std::declval<T>().begin())>, void>>
1089  : public std::true_type {};
1090 
1091 // check to see if an object is a wrapper (fail by default)
1092 template <typename T, typename _ = void> struct is_wrapper : std::false_type {};
1093 
1094 // check if an object is a wrapper (it has a value_type defined)
1095 template <typename T>
1096 struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> : public std::true_type {};
1097 
1098 // Check for tuple like types, as in classes with a tuple_size type trait
1099 template <typename S> class is_tuple_like {
1100  template <typename SS>
1101  // static auto test(int)
1102  // -> decltype(std::conditional<(std::tuple_size<SS>::value > 0), std::true_type, std::false_type>::type());
1103  static auto test(int) -> decltype(std::tuple_size<typename std::decay<SS>::type>::value, std::true_type{});
1104  template <typename> static auto test(...) -> std::false_type;
1105 
1106  public:
1107  static constexpr bool value = decltype(test<S>(0))::value;
1108 };
1109 
1111 template <typename T, enable_if_t<std::is_convertible<T, std::string>::value, detail::enabler> = detail::dummy>
1112 auto to_string(T &&value) -> decltype(std::forward<T>(value)) {
1113  return std::forward<T>(value);
1114 }
1115 
1117 template <typename T,
1118  enable_if_t<std::is_constructible<std::string, T>::value && !std::is_convertible<T, std::string>::value,
1119  detail::enabler> = detail::dummy>
1120 std::string to_string(const T &value) {
1121  return std::string(value);
1122 }
1123 
1125 template <typename T,
1126  enable_if_t<!std::is_convertible<std::string, T>::value && !std::is_constructible<std::string, T>::value &&
1128  detail::enabler> = detail::dummy>
1129 std::string to_string(T &&value) {
1130  std::stringstream stream;
1131  stream << value;
1132  return stream.str();
1133 }
1134 
1136 template <typename T,
1137  enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
1139  detail::enabler> = detail::dummy>
1140 std::string to_string(T &&) {
1141  return std::string{};
1142 }
1143 
1145 template <typename T,
1146  enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
1148  detail::enabler> = detail::dummy>
1149 std::string to_string(T &&variable) {
1150  std::vector<std::string> defaults;
1151  auto cval = variable.begin();
1152  auto end = variable.end();
1153  while(cval != end) {
1154  defaults.emplace_back(CLI::detail::to_string(*cval));
1155  ++cval;
1156  }
1157  return std::string("[" + detail::join(defaults) + "]");
1158 }
1159 
1161 template <typename T1,
1162  typename T2,
1163  typename T,
1164  enable_if_t<std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
1165 auto checked_to_string(T &&value) -> decltype(to_string(std::forward<T>(value))) {
1166  return to_string(std::forward<T>(value));
1167 }
1168 
1170 template <typename T1,
1171  typename T2,
1172  typename T,
1173  enable_if_t<!std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
1174 std::string checked_to_string(T &&) {
1175  return std::string{};
1176 }
1178 template <typename T, enable_if_t<std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
1179 std::string value_string(const T &value) {
1180  return std::to_string(value);
1181 }
1183 template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
1184 std::string value_string(const T &value) {
1185  return std::to_string(static_cast<typename std::underlying_type<T>::type>(value));
1186 }
1188 template <typename T,
1189  enable_if_t<!std::is_enum<T>::value && !std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
1190 auto value_string(const T &value) -> decltype(to_string(value)) {
1191  return to_string(value);
1192 }
1193 
1195 template <typename T, typename def, typename Enable = void> struct wrapped_type { using type = def; };
1196 
1198 template <typename T, typename def> struct wrapped_type<T, def, typename std::enable_if<is_wrapper<T>::value>::type> {
1199  using type = typename T::value_type;
1200 };
1201 
1203 template <typename T, typename Enable = void> struct type_count_base { static const int value{0}; };
1204 
1206 template <typename T>
1208  typename std::enable_if<!is_tuple_like<T>::value && !is_mutable_container<T>::value &&
1209  !std::is_void<T>::value>::type> {
1210  static constexpr int value{1};
1211 };
1212 
1214 template <typename T>
1215 struct type_count_base<T, typename std::enable_if<is_tuple_like<T>::value && !is_mutable_container<T>::value>::type> {
1216  static constexpr int value{std::tuple_size<T>::value};
1217 };
1218 
1220 template <typename T> struct type_count_base<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1221  static constexpr int value{type_count_base<typename T::value_type>::value};
1222 };
1223 
1225 
1227 template <typename T> struct subtype_count;
1228 
1230 template <typename T> struct subtype_count_min;
1231 
1233 template <typename T, typename Enable = void> struct type_count { static const int value{0}; };
1234 
1236 template <typename T>
1237 struct type_count<T,
1238  typename std::enable_if<!is_wrapper<T>::value && !is_tuple_like<T>::value && !is_complex<T>::value &&
1239  !std::is_void<T>::value>::type> {
1240  static constexpr int value{1};
1241 };
1242 
1244 template <typename T> struct type_count<T, typename std::enable_if<is_complex<T>::value>::type> {
1245  static constexpr int value{2};
1246 };
1247 
1249 template <typename T> struct type_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1250  static constexpr int value{subtype_count<typename T::value_type>::value};
1251 };
1252 
1254 template <typename T>
1255 struct type_count<T,
1256  typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value &&
1257  !is_mutable_container<T>::value>::type> {
1258  static constexpr int value{type_count<typename T::value_type>::value};
1259 };
1260 
1262 template <typename T, std::size_t I>
1263 constexpr typename std::enable_if<I == type_count_base<T>::value, int>::type tuple_type_size() {
1264  return 0;
1265 }
1266 
1268 template <typename T, std::size_t I>
1269  constexpr typename std::enable_if < I<type_count_base<T>::value, int>::type tuple_type_size() {
1270  return subtype_count<typename std::tuple_element<I, T>::type>::value + tuple_type_size<T, I + 1>();
1271 }
1272 
1274 template <typename T> struct type_count<T, typename std::enable_if<is_tuple_like<T>::value>::type> {
1275  static constexpr int value{tuple_type_size<T, 0>()};
1276 };
1277 
1279 template <typename T> struct subtype_count {
1280  static constexpr int value{is_mutable_container<T>::value ? expected_max_vector_size : type_count<T>::value};
1281 };
1282 
1284 template <typename T, typename Enable = void> struct type_count_min { static const int value{0}; };
1285 
1287 template <typename T>
1288 struct type_count_min<
1289  T,
1290  typename std::enable_if<!is_mutable_container<T>::value && !is_tuple_like<T>::value && !is_wrapper<T>::value &&
1291  !is_complex<T>::value && !std::is_void<T>::value>::type> {
1292  static constexpr int value{type_count<T>::value};
1293 };
1294 
1296 template <typename T> struct type_count_min<T, typename std::enable_if<is_complex<T>::value>::type> {
1297  static constexpr int value{1};
1298 };
1299 
1301 template <typename T>
1302 struct type_count_min<
1303  T,
1304  typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value>::type> {
1305  static constexpr int value{subtype_count_min<typename T::value_type>::value};
1306 };
1307 
1309 template <typename T, std::size_t I>
1310 constexpr typename std::enable_if<I == type_count_base<T>::value, int>::type tuple_type_size_min() {
1311  return 0;
1312 }
1313 
1315 template <typename T, std::size_t I>
1316  constexpr typename std::enable_if < I<type_count_base<T>::value, int>::type tuple_type_size_min() {
1317  return subtype_count_min<typename std::tuple_element<I, T>::type>::value + tuple_type_size_min<T, I + 1>();
1318 }
1319 
1321 template <typename T> struct type_count_min<T, typename std::enable_if<is_tuple_like<T>::value>::type> {
1322  static constexpr int value{tuple_type_size_min<T, 0>()};
1323 };
1324 
1326 template <typename T> struct subtype_count_min {
1327  static constexpr int value{is_mutable_container<T>::value
1328  ? ((type_count<T>::value < expected_max_vector_size) ? type_count<T>::value : 0)
1329  : type_count_min<T>::value};
1330 };
1331 
1333 template <typename T, typename Enable = void> struct expected_count { static const int value{0}; };
1334 
1336 template <typename T>
1337 struct expected_count<T,
1338  typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
1339  !std::is_void<T>::value>::type> {
1340  static constexpr int value{1};
1341 };
1343 template <typename T> struct expected_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1344  static constexpr int value{expected_max_vector_size};
1345 };
1346 
1348 template <typename T>
1349 struct expected_count<T, typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value>::type> {
1350  static constexpr int value{expected_count<typename T::value_type>::value};
1351 };
1352 
1353 // Enumeration of the different supported categorizations of objects
1354 enum class object_category : int {
1355  char_value = 1,
1356  integral_value = 2,
1357  unsigned_integral = 4,
1358  enumeration = 6,
1359  boolean_value = 8,
1360  floating_point = 10,
1361  number_constructible = 12,
1362  double_constructible = 14,
1363  integer_constructible = 16,
1364  // string like types
1365  string_assignable = 23,
1366  string_constructible = 24,
1367  other = 45,
1368  // special wrapper or container types
1369  wrapper_value = 50,
1370  complex_number = 60,
1371  tuple_value = 70,
1372  container_value = 80,
1373 
1374 };
1375 
1377 
1379 template <typename T, typename Enable = void> struct classify_object {
1380  static constexpr object_category value{object_category::other};
1381 };
1382 
1384 template <typename T>
1385 struct classify_object<
1386  T,
1387  typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && std::is_signed<T>::value &&
1388  !is_bool<T>::value && !std::is_enum<T>::value>::type> {
1389  static constexpr object_category value{object_category::integral_value};
1390 };
1391 
1393 template <typename T>
1394 struct classify_object<T,
1395  typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value &&
1396  !std::is_same<T, char>::value && !is_bool<T>::value>::type> {
1397  static constexpr object_category value{object_category::unsigned_integral};
1398 };
1399 
1401 template <typename T>
1402 struct classify_object<T, typename std::enable_if<std::is_same<T, char>::value && !std::is_enum<T>::value>::type> {
1403  static constexpr object_category value{object_category::char_value};
1404 };
1405 
1407 template <typename T> struct classify_object<T, typename std::enable_if<is_bool<T>::value>::type> {
1408  static constexpr object_category value{object_category::boolean_value};
1409 };
1410 
1412 template <typename T> struct classify_object<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
1413  static constexpr object_category value{object_category::floating_point};
1414 };
1415 
1417 template <typename T>
1418 struct classify_object<T,
1419  typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1420  std::is_assignable<T &, std::string>::value>::type> {
1421  static constexpr object_category value{object_category::string_assignable};
1422 };
1423 
1425 template <typename T>
1426 struct classify_object<
1427  T,
1428  typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1429  !std::is_assignable<T &, std::string>::value && (type_count<T>::value == 1) &&
1430  std::is_constructible<T, std::string>::value>::type> {
1431  static constexpr object_category value{object_category::string_constructible};
1432 };
1433 
1435 template <typename T> struct classify_object<T, typename std::enable_if<std::is_enum<T>::value>::type> {
1436  static constexpr object_category value{object_category::enumeration};
1437 };
1438 
1439 template <typename T> struct classify_object<T, typename std::enable_if<is_complex<T>::value>::type> {
1440  static constexpr object_category value{object_category::complex_number};
1441 };
1442 
1445 template <typename T> struct uncommon_type {
1446  using type = typename std::conditional<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1447  !std::is_assignable<T &, std::string>::value &&
1448  !std::is_constructible<T, std::string>::value && !is_complex<T>::value &&
1449  !is_mutable_container<T>::value && !std::is_enum<T>::value,
1450  std::true_type,
1451  std::false_type>::type;
1452  static constexpr bool value = type::value;
1453 };
1454 
1456 template <typename T>
1457 struct classify_object<T,
1458  typename std::enable_if<(!is_mutable_container<T>::value && is_wrapper<T>::value &&
1459  !is_tuple_like<T>::value && uncommon_type<T>::value)>::type> {
1460  static constexpr object_category value{object_category::wrapper_value};
1461 };
1462 
1464 template <typename T>
1465 struct classify_object<T,
1466  typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1467  !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
1468  is_direct_constructible<T, int>::value>::type> {
1469  static constexpr object_category value{object_category::number_constructible};
1470 };
1471 
1473 template <typename T>
1474 struct classify_object<T,
1475  typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1476  !is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
1477  is_direct_constructible<T, int>::value>::type> {
1478  static constexpr object_category value{object_category::integer_constructible};
1479 };
1480 
1482 template <typename T>
1483 struct classify_object<T,
1484  typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1485  !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
1486  !is_direct_constructible<T, int>::value>::type> {
1487  static constexpr object_category value{object_category::double_constructible};
1488 };
1489 
1491 template <typename T>
1492 struct classify_object<
1493  T,
1494  typename std::enable_if<is_tuple_like<T>::value &&
1495  ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
1496  (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
1497  !is_direct_constructible<T, int>::value))>::type> {
1498  static constexpr object_category value{object_category::tuple_value};
1499  // the condition on this class requires it be like a tuple, but on some compilers (like Xcode) tuples can be
1500  // constructed from just the first element so tuples of <string, int,int> can be constructed from a string, which
1501  // could lead to issues so there are two variants of the condition, the first isolates things with a type size >=2
1502  // mainly to get tuples on Xcode with the exception of wrappers, the second is the main one and just separating out
1503  // those cases that are caught by other object classifications
1504 };
1505 
1507 template <typename T> struct classify_object<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1508  static constexpr object_category value{object_category::container_value};
1509 };
1510 
1511 // Type name print
1512 
1516 
1517 template <typename T,
1518  enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
1519 constexpr const char *type_name() {
1520  return "CHAR";
1521 }
1522 
1523 template <typename T,
1524  enable_if_t<classify_object<T>::value == object_category::integral_value ||
1525  classify_object<T>::value == object_category::integer_constructible,
1526  detail::enabler> = detail::dummy>
1527 constexpr const char *type_name() {
1528  return "INT";
1529 }
1530 
1531 template <typename T,
1532  enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
1533 constexpr const char *type_name() {
1534  return "UINT";
1535 }
1536 
1537 template <typename T,
1538  enable_if_t<classify_object<T>::value == object_category::floating_point ||
1539  classify_object<T>::value == object_category::number_constructible ||
1540  classify_object<T>::value == object_category::double_constructible,
1541  detail::enabler> = detail::dummy>
1542 constexpr const char *type_name() {
1543  return "FLOAT";
1544 }
1545 
1547 template <typename T,
1548  enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
1549 constexpr const char *type_name() {
1550  return "ENUM";
1551 }
1552 
1554 template <typename T,
1555  enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
1556 constexpr const char *type_name() {
1557  return "BOOLEAN";
1558 }
1559 
1561 template <typename T,
1562  enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
1563 constexpr const char *type_name() {
1564  return "COMPLEX";
1565 }
1566 
1568 template <typename T,
1569  enable_if_t<classify_object<T>::value >= object_category::string_assignable &&
1570  classify_object<T>::value <= object_category::other,
1571  detail::enabler> = detail::dummy>
1572 constexpr const char *type_name() {
1573  return "TEXT";
1574 }
1576 template <typename T,
1577  enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
1578  detail::enabler> = detail::dummy>
1579 std::string type_name(); // forward declaration
1580 
1582 template <typename T,
1583  enable_if_t<classify_object<T>::value == object_category::container_value ||
1584  classify_object<T>::value == object_category::wrapper_value,
1585  detail::enabler> = detail::dummy>
1586 std::string type_name(); // forward declaration
1587 
1589 template <typename T,
1590  enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value == 1,
1591  detail::enabler> = detail::dummy>
1592 inline std::string type_name() {
1593  return type_name<typename std::decay<typename std::tuple_element<0, T>::type>::type>();
1594 }
1595 
1597 template <typename T, std::size_t I>
1598 inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_name() {
1599  return std::string{};
1600 }
1601 
1603 template <typename T, std::size_t I>
1604 inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_name() {
1605  std::string str = std::string(type_name<typename std::decay<typename std::tuple_element<I, T>::type>::type>()) +
1606  ',' + tuple_name<T, I + 1>();
1607  if(str.back() == ',')
1608  str.pop_back();
1609  return str;
1610 }
1611 
1613 template <typename T,
1614  enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
1615  detail::enabler>>
1616 inline std::string type_name() {
1617  auto tname = std::string(1, '[') + tuple_name<T, 0>();
1618  tname.push_back(']');
1619  return tname;
1620 }
1621 
1623 template <typename T,
1624  enable_if_t<classify_object<T>::value == object_category::container_value ||
1625  classify_object<T>::value == object_category::wrapper_value,
1626  detail::enabler>>
1627 inline std::string type_name() {
1628  return type_name<typename T::value_type>();
1629 }
1630 
1631 // Lexical cast
1632 
1634 template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
1635 bool integral_conversion(const std::string &input, T &output) noexcept {
1636  if(input.empty()) {
1637  return false;
1638  }
1639  char *val = nullptr;
1640  std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0);
1641  output = static_cast<T>(output_ll);
1642  return val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll;
1643 }
1644 
1646 template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
1647 bool integral_conversion(const std::string &input, T &output) noexcept {
1648  if(input.empty()) {
1649  return false;
1650  }
1651  char *val = nullptr;
1652  std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0);
1653  output = static_cast<T>(output_ll);
1654  return val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll;
1655 }
1656 
1658 inline std::int64_t to_flag_value(std::string val) {
1659  static const std::string trueString("true");
1660  static const std::string falseString("false");
1661  if(val == trueString) {
1662  return 1;
1663  }
1664  if(val == falseString) {
1665  return -1;
1666  }
1667  val = detail::to_lower(val);
1668  std::int64_t ret;
1669  if(val.size() == 1) {
1670  if(val[0] >= '1' && val[0] <= '9') {
1671  return (static_cast<std::int64_t>(val[0]) - '0');
1672  }
1673  switch(val[0]) {
1674  case '0':
1675  case 'f':
1676  case 'n':
1677  case '-':
1678  ret = -1;
1679  break;
1680  case 't':
1681  case 'y':
1682  case '+':
1683  ret = 1;
1684  break;
1685  default:
1686  throw std::invalid_argument("unrecognized character");
1687  }
1688  return ret;
1689  }
1690  if(val == trueString || val == "on" || val == "yes" || val == "enable") {
1691  ret = 1;
1692  } else if(val == falseString || val == "off" || val == "no" || val == "disable") {
1693  ret = -1;
1694  } else {
1695  ret = std::stoll(val);
1696  }
1697  return ret;
1698 }
1699 
1701 template <typename T,
1702  enable_if_t<classify_object<T>::value == object_category::integral_value ||
1703  classify_object<T>::value == object_category::unsigned_integral,
1704  detail::enabler> = detail::dummy>
1705 bool lexical_cast(const std::string &input, T &output) {
1706  return integral_conversion(input, output);
1707 }
1708 
1710 template <typename T,
1711  enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
1712 bool lexical_cast(const std::string &input, T &output) {
1713  if(input.size() == 1) {
1714  output = static_cast<T>(input[0]);
1715  return true;
1716  }
1717  return integral_conversion(input, output);
1718 }
1719 
1721 template <typename T,
1722  enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
1723 bool lexical_cast(const std::string &input, T &output) {
1724  try {
1725  auto out = to_flag_value(input);
1726  output = (out > 0);
1727  return true;
1728  } catch(const std::invalid_argument &) {
1729  return false;
1730  } catch(const std::out_of_range &) {
1731  // if the number is out of the range of a 64 bit value then it is still a number and for this purpose is still
1732  // valid all we care about the sign
1733  output = (input[0] != '-');
1734  return true;
1735  }
1736 }
1737 
1739 template <typename T,
1740  enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> = detail::dummy>
1741 bool lexical_cast(const std::string &input, T &output) {
1742  if(input.empty()) {
1743  return false;
1744  }
1745  char *val = nullptr;
1746  auto output_ld = std::strtold(input.c_str(), &val);
1747  output = static_cast<T>(output_ld);
1748  return val == (input.c_str() + input.size());
1749 }
1750 
1752 template <typename T,
1753  enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
1754 bool lexical_cast(const std::string &input, T &output) {
1755  using XC = typename wrapped_type<T, double>::type;
1756  XC x{0.0}, y{0.0};
1757  auto str1 = input;
1758  bool worked = false;
1759  auto nloc = str1.find_last_of("+-");
1760  if(nloc != std::string::npos && nloc > 0) {
1761  worked = detail::lexical_cast(str1.substr(0, nloc), x);
1762  str1 = str1.substr(nloc);
1763  if(str1.back() == 'i' || str1.back() == 'j')
1764  str1.pop_back();
1765  worked = worked && detail::lexical_cast(str1, y);
1766  } else {
1767  if(str1.back() == 'i' || str1.back() == 'j') {
1768  str1.pop_back();
1769  worked = detail::lexical_cast(str1, y);
1770  x = XC{0};
1771  } else {
1772  worked = detail::lexical_cast(str1, x);
1773  y = XC{0};
1774  }
1775  }
1776  if(worked) {
1777  output = T{x, y};
1778  return worked;
1779  }
1780  return from_stream(input, output);
1781 }
1782 
1784 template <typename T,
1785  enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> = detail::dummy>
1786 bool lexical_cast(const std::string &input, T &output) {
1787  output = input;
1788  return true;
1789 }
1790 
1792 template <
1793  typename T,
1794  enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> = detail::dummy>
1795 bool lexical_cast(const std::string &input, T &output) {
1796  output = T(input);
1797  return true;
1798 }
1799 
1801 template <typename T,
1802  enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
1803 bool lexical_cast(const std::string &input, T &output) {
1804  typename std::underlying_type<T>::type val;
1805  if(!integral_conversion(input, val)) {
1806  return false;
1807  }
1808  output = static_cast<T>(val);
1809  return true;
1810 }
1811 
1813 template <typename T,
1814  enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
1815  std::is_assignable<T &, typename T::value_type>::value,
1816  detail::enabler> = detail::dummy>
1817 bool lexical_cast(const std::string &input, T &output) {
1818  typename T::value_type val;
1819  if(lexical_cast(input, val)) {
1820  output = val;
1821  return true;
1822  }
1823  return from_stream(input, output);
1824 }
1825 
1826 template <typename T,
1827  enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
1828  !std::is_assignable<T &, typename T::value_type>::value && std::is_assignable<T &, T>::value,
1829  detail::enabler> = detail::dummy>
1830 bool lexical_cast(const std::string &input, T &output) {
1831  typename T::value_type val;
1832  if(lexical_cast(input, val)) {
1833  output = T{val};
1834  return true;
1835  }
1836  return from_stream(input, output);
1837 }
1838 
1840 template <
1841  typename T,
1842  enable_if_t<classify_object<T>::value == object_category::number_constructible, detail::enabler> = detail::dummy>
1843 bool lexical_cast(const std::string &input, T &output) {
1844  int val;
1845  if(integral_conversion(input, val)) {
1846  output = T(val);
1847  return true;
1848  } else {
1849  double dval;
1850  if(lexical_cast(input, dval)) {
1851  output = T{dval};
1852  return true;
1853  }
1854  }
1855  return from_stream(input, output);
1856 }
1857 
1859 template <
1860  typename T,
1861  enable_if_t<classify_object<T>::value == object_category::integer_constructible, detail::enabler> = detail::dummy>
1862 bool lexical_cast(const std::string &input, T &output) {
1863  int val;
1864  if(integral_conversion(input, val)) {
1865  output = T(val);
1866  return true;
1867  }
1868  return from_stream(input, output);
1869 }
1870 
1872 template <
1873  typename T,
1874  enable_if_t<classify_object<T>::value == object_category::double_constructible, detail::enabler> = detail::dummy>
1875 bool lexical_cast(const std::string &input, T &output) {
1876  double val;
1877  if(lexical_cast(input, val)) {
1878  output = T{val};
1879  return true;
1880  }
1881  return from_stream(input, output);
1882 }
1883 
1885 template <typename T,
1886  enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
1887  detail::enabler> = detail::dummy>
1888 bool lexical_cast(const std::string &input, T &output) {
1889  int val;
1890  if(integral_conversion(input, val)) {
1891 #ifdef _MSC_VER
1892 #pragma warning(push)
1893 #pragma warning(disable : 4800)
1894 #endif
1895  // with Atomic<XX> this could produce a warning due to the conversion but if atomic gets here it is an old style
1896  // so will most likely still work
1897  output = val;
1898 #ifdef _MSC_VER
1899 #pragma warning(pop)
1900 #endif
1901  return true;
1902  }
1903  // LCOV_EXCL_START
1904  // This version of cast is only used for odd cases in an older compilers the fail over
1905  // from_stream is tested elsewhere an not relevant for coverage here
1906  return from_stream(input, output);
1907  // LCOV_EXCL_STOP
1908 }
1909 
1911 template <typename T,
1912  enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value,
1913  detail::enabler> = detail::dummy>
1914 bool lexical_cast(const std::string &input, T &output) {
1915  static_assert(is_istreamable<T>::value,
1916  "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it "
1917  "is convertible from another type use the add_option<T, XC>(...) with XC being the known type");
1918  return from_stream(input, output);
1919 }
1920 
1923 template <typename AssignTo,
1924  typename ConvertTo,
1925  enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
1926  (classify_object<AssignTo>::value == object_category::string_assignable ||
1927  classify_object<AssignTo>::value == object_category::string_constructible),
1928  detail::enabler> = detail::dummy>
1929 bool lexical_assign(const std::string &input, AssignTo &output) {
1930  return lexical_cast(input, output);
1931 }
1932 
1934 template <typename AssignTo,
1935  typename ConvertTo,
1936  enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
1937  classify_object<AssignTo>::value != object_category::string_assignable &&
1938  classify_object<AssignTo>::value != object_category::string_constructible,
1939  detail::enabler> = detail::dummy>
1940 bool lexical_assign(const std::string &input, AssignTo &output) {
1941  if(input.empty()) {
1942  output = AssignTo{};
1943  return true;
1944  }
1945 
1946  return lexical_cast(input, output);
1947 }
1948 
1950 template <typename AssignTo,
1951  typename ConvertTo,
1952  enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
1953  classify_object<AssignTo>::value == object_category::wrapper_value,
1954  detail::enabler> = detail::dummy>
1955 bool lexical_assign(const std::string &input, AssignTo &output) {
1956  if(input.empty()) {
1957  typename AssignTo::value_type emptyVal{};
1958  output = emptyVal;
1959  return true;
1960  }
1961  return lexical_cast(input, output);
1962 }
1963 
1966 template <typename AssignTo,
1967  typename ConvertTo,
1968  enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
1969  classify_object<AssignTo>::value != object_category::wrapper_value &&
1970  std::is_assignable<AssignTo &, int>::value,
1971  detail::enabler> = detail::dummy>
1972 bool lexical_assign(const std::string &input, AssignTo &output) {
1973  if(input.empty()) {
1974  output = 0;
1975  return true;
1976  }
1977  int val;
1978  if(lexical_cast(input, val)) {
1979  output = val;
1980  return true;
1981  }
1982  return false;
1983 }
1984 
1986 template <typename AssignTo,
1987  typename ConvertTo,
1988  enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, ConvertTo &>::value,
1989  detail::enabler> = detail::dummy>
1990 bool lexical_assign(const std::string &input, AssignTo &output) {
1991  ConvertTo val{};
1992  bool parse_result = (!input.empty()) ? lexical_cast<ConvertTo>(input, val) : true;
1993  if(parse_result) {
1994  output = val;
1995  }
1996  return parse_result;
1997 }
1998 
2000 template <
2001  typename AssignTo,
2002  typename ConvertTo,
2003  enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, ConvertTo &>::value &&
2004  std::is_move_assignable<AssignTo>::value,
2005  detail::enabler> = detail::dummy>
2006 bool lexical_assign(const std::string &input, AssignTo &output) {
2007  ConvertTo val{};
2008  bool parse_result = input.empty() ? true : lexical_cast<ConvertTo>(input, val);
2009  if(parse_result) {
2010  output = AssignTo(val); // use () form of constructor to allow some implicit conversions
2011  }
2012  return parse_result;
2013 }
2014 
2016 template <typename AssignTo,
2017  typename ConvertTo,
2018  enable_if_t<classify_object<ConvertTo>::value <= object_category::other &&
2019  classify_object<AssignTo>::value <= object_category::wrapper_value,
2020  detail::enabler> = detail::dummy>
2021 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2022  return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2023 }
2024 
2027 template <typename AssignTo,
2028  typename ConvertTo,
2029  enable_if_t<(type_count<AssignTo>::value <= 2) && expected_count<AssignTo>::value == 1 &&
2031  detail::enabler> = detail::dummy>
2032 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2033  // the remove const is to handle pair types coming from a container
2034  typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type v1;
2035  typename std::tuple_element<1, ConvertTo>::type v2;
2036  bool retval = lexical_assign<decltype(v1), decltype(v1)>(strings[0], v1);
2037  if(strings.size() > 1) {
2038  retval = retval && lexical_assign<decltype(v2), decltype(v2)>(strings[1], v2);
2039  }
2040  if(retval) {
2041  output = AssignTo{v1, v2};
2042  }
2043  return retval;
2044 }
2045 
2047 template <class AssignTo,
2048  class ConvertTo,
2049  enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2051  detail::enabler> = detail::dummy>
2052 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2053  output.erase(output.begin(), output.end());
2054  for(const auto &elem : strings) {
2055  typename AssignTo::value_type out;
2056  bool retval = lexical_assign<typename AssignTo::value_type, typename ConvertTo::value_type>(elem, out);
2057  if(!retval) {
2058  return false;
2059  }
2060  output.insert(output.end(), std::move(out));
2061  }
2062  return (!output.empty());
2063 }
2064 
2066 template <class AssignTo, class ConvertTo, enable_if_t<is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
2067 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
2068 
2069  if(strings.size() >= 2 && !strings[1].empty()) {
2070  using XC2 = typename wrapped_type<ConvertTo, double>::type;
2071  XC2 x{0.0}, y{0.0};
2072  auto str1 = strings[1];
2073  if(str1.back() == 'i' || str1.back() == 'j') {
2074  str1.pop_back();
2075  }
2076  auto worked = detail::lexical_cast(strings[0], x) && detail::lexical_cast(str1, y);
2077  if(worked) {
2078  output = ConvertTo{x, y};
2079  }
2080  return worked;
2081  } else {
2082  return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2083  }
2084 }
2085 
2087 template <class AssignTo,
2088  class ConvertTo,
2089  enable_if_t<is_mutable_container<AssignTo>::value && (expected_count<ConvertTo>::value == 1) &&
2090  (type_count<ConvertTo>::value == 1),
2091  detail::enabler> = detail::dummy>
2092 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2093  bool retval = true;
2094  output.clear();
2095  output.reserve(strings.size());
2096  for(const auto &elem : strings) {
2097 
2098  output.emplace_back();
2099  retval = retval && lexical_assign<typename AssignTo::value_type, ConvertTo>(elem, output.back());
2100  }
2101  return (!output.empty()) && retval;
2102 }
2103 
2104 // forward declaration
2105 
2107 template <class AssignTo,
2108  class ConvertTo,
2109  enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2111  detail::enabler> = detail::dummy>
2112 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
2113 
2115 template <class AssignTo,
2116  class ConvertTo,
2117  enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2118  type_count_base<ConvertTo>::value != 2 &&
2119  ((type_count<ConvertTo>::value > 2) ||
2120  (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
2121  detail::enabler> = detail::dummy>
2122 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output);
2123 
2125 template <class AssignTo,
2126  class ConvertTo,
2127  enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
2128  (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
2129  type_count<ConvertTo>::value > 2),
2130  detail::enabler> = detail::dummy>
2131 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output); // forward declaration
2132 
2135 template <typename AssignTo,
2136  typename ConvertTo,
2137  enable_if_t<!is_tuple_like<AssignTo>::value && !is_mutable_container<AssignTo>::value &&
2138  classify_object<ConvertTo>::value != object_category::wrapper_value &&
2139  (is_mutable_container<ConvertTo>::value || type_count<ConvertTo>::value > 2),
2140  detail::enabler> = detail::dummy>
2141 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2142 
2143  if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
2144  ConvertTo val;
2145  auto retval = lexical_conversion<ConvertTo, ConvertTo>(strings, val);
2146  output = AssignTo{val};
2147  return retval;
2148  }
2149  output = AssignTo{};
2150  return true;
2151 }
2152 
2154 template <class AssignTo, class ConvertTo, std::size_t I>
2155 inline typename std::enable_if<(I >= type_count_base<AssignTo>::value), bool>::type
2156 tuple_conversion(const std::vector<std::string> &, AssignTo &) {
2157  return true;
2158 }
2159 
2161 template <class AssignTo, class ConvertTo>
2162 inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && type_count<ConvertTo>::value == 1, bool>::type
2163 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2164  auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2165  strings.erase(strings.begin());
2166  return retval;
2167 }
2168 
2170 template <class AssignTo, class ConvertTo>
2171 inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && (type_count<ConvertTo>::value > 1) &&
2172  type_count<ConvertTo>::value == type_count_min<ConvertTo>::value,
2173  bool>::type
2174 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2175  auto retval = lexical_conversion<AssignTo, ConvertTo>(strings, output);
2176  strings.erase(strings.begin(), strings.begin() + type_count<ConvertTo>::value);
2177  return retval;
2178 }
2179 
2181 template <class AssignTo, class ConvertTo>
2182 inline typename std::enable_if<is_mutable_container<ConvertTo>::value ||
2183  type_count<ConvertTo>::value != type_count_min<ConvertTo>::value,
2184  bool>::type
2185 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2186 
2187  std::size_t index{subtype_count_min<ConvertTo>::value};
2188  const std::size_t mx_count{subtype_count<ConvertTo>::value};
2189  const std::size_t mx{(std::max)(mx_count, strings.size())};
2190 
2191  while(index < mx) {
2192  if(is_separator(strings[index])) {
2193  break;
2194  }
2195  ++index;
2196  }
2197  bool retval = lexical_conversion<AssignTo, ConvertTo>(
2198  std::vector<std::string>(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index)), output);
2199  strings.erase(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index) + 1);
2200  return retval;
2201 }
2202 
2204 template <class AssignTo, class ConvertTo, std::size_t I>
2205 inline typename std::enable_if<(I < type_count_base<AssignTo>::value), bool>::type
2206 tuple_conversion(std::vector<std::string> strings, AssignTo &output) {
2207  bool retval = true;
2208  using ConvertToElement = typename std::
2209  conditional<is_tuple_like<ConvertTo>::value, typename std::tuple_element<I, ConvertTo>::type, ConvertTo>::type;
2210  if(!strings.empty()) {
2211  retval = retval && tuple_type_conversion<typename std::tuple_element<I, AssignTo>::type, ConvertToElement>(
2212  strings, std::get<I>(output));
2213  }
2214  retval = retval && tuple_conversion<AssignTo, ConvertTo, I + 1>(std::move(strings), output);
2215  return retval;
2216 }
2217 
2219 template <class AssignTo,
2220  class ConvertTo,
2221  enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2222  type_count_base<ConvertTo>::value == 2,
2223  detail::enabler>>
2224 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output) {
2225  output.clear();
2226  while(!strings.empty()) {
2227 
2228  typename std::remove_const<typename std::tuple_element<0, typename ConvertTo::value_type>::type>::type v1;
2229  typename std::tuple_element<1, typename ConvertTo::value_type>::type v2;
2230  bool retval = tuple_type_conversion<decltype(v1), decltype(v1)>(strings, v1);
2231  if(!strings.empty()) {
2232  retval = retval && tuple_type_conversion<decltype(v2), decltype(v2)>(strings, v2);
2233  }
2234  if(retval) {
2235  output.insert(output.end(), typename AssignTo::value_type{v1, v2});
2236  } else {
2237  return false;
2238  }
2239  }
2240  return (!output.empty());
2241 }
2242 
2244 template <class AssignTo,
2245  class ConvertTo,
2246  enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
2247  (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
2248  type_count<ConvertTo>::value > 2),
2249  detail::enabler>>
2250 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2251  static_assert(
2252  !is_tuple_like<ConvertTo>::value || type_count_base<AssignTo>::value == type_count_base<ConvertTo>::value,
2253  "if the conversion type is defined as a tuple it must be the same size as the type you are converting to");
2254  return tuple_conversion<AssignTo, ConvertTo, 0>(strings, output);
2255 }
2256 
2258 template <class AssignTo,
2259  class ConvertTo,
2260  enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2261  type_count_base<ConvertTo>::value != 2 &&
2262  ((type_count<ConvertTo>::value > 2) ||
2263  (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
2264  detail::enabler>>
2265 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
2266  bool retval = true;
2267  output.clear();
2268  std::vector<std::string> temp;
2269  std::size_t ii{0};
2270  std::size_t icount{0};
2271  std::size_t xcm{type_count<ConvertTo>::value};
2272  auto ii_max = strings.size();
2273  while(ii < ii_max) {
2274  temp.push_back(strings[ii]);
2275  ++ii;
2276  ++icount;
2277  if(icount == xcm || is_separator(temp.back()) || ii == ii_max) {
2278  if(static_cast<int>(xcm) > type_count_min<ConvertTo>::value && is_separator(temp.back())) {
2279  temp.pop_back();
2280  }
2281  typename AssignTo::value_type temp_out;
2282  retval = retval &&
2283  lexical_conversion<typename AssignTo::value_type, typename ConvertTo::value_type>(temp, temp_out);
2284  temp.clear();
2285  if(!retval) {
2286  return false;
2287  }
2288  output.insert(output.end(), std::move(temp_out));
2289  icount = 0;
2290  }
2291  }
2292  return retval;
2293 }
2294 
2296 template <typename AssignTo,
2297  class ConvertTo,
2298  enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
2299  std::is_assignable<ConvertTo &, ConvertTo>::value,
2300  detail::enabler> = detail::dummy>
2301 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
2302  if(strings.empty() || strings.front().empty()) {
2303  output = ConvertTo{};
2304  return true;
2305  }
2306  typename ConvertTo::value_type val;
2307  if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
2308  output = ConvertTo{val};
2309  return true;
2310  }
2311  return false;
2312 }
2313 
2315 template <typename AssignTo,
2316  class ConvertTo,
2317  enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
2318  !std::is_assignable<AssignTo &, ConvertTo>::value,
2319  detail::enabler> = detail::dummy>
2320 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
2321  using ConvertType = typename ConvertTo::value_type;
2322  if(strings.empty() || strings.front().empty()) {
2323  output = ConvertType{};
2324  return true;
2325  }
2326  ConvertType val;
2327  if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
2328  output = val;
2329  return true;
2330  }
2331  return false;
2332 }
2333 
2339 template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
2340 void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
2341  std::int64_t count{0};
2342  for(auto &flag : flags) {
2343  count += detail::to_flag_value(flag);
2344  }
2345  output = (count > 0) ? static_cast<T>(count) : T{0};
2346 }
2347 
2353 template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
2354 void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
2355  std::int64_t count{0};
2356  for(auto &flag : flags) {
2357  count += detail::to_flag_value(flag);
2358  }
2359  output = static_cast<T>(count);
2360 }
2361 
2362 #ifdef _MSC_VER
2363 #pragma warning(push)
2364 #pragma warning(disable : 4800)
2365 #endif
2366 // with Atomic<XX> this could produce a warning due to the conversion but if atomic gets here it is an old style so will
2367 // most likely still work
2368 
2374 template <typename T,
2375  enable_if_t<!std::is_signed<T>::value && !std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
2376 void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
2377  std::int64_t count{0};
2378  for(auto &flag : flags) {
2379  count += detail::to_flag_value(flag);
2380  }
2381  std::string out = detail::to_string(count);
2382  lexical_cast(out, output);
2383 }
2384 
2385 #ifdef _MSC_VER
2386 #pragma warning(pop)
2387 #endif
2388 
2389 } // namespace detail
2390 
2391 
2392 
2393 namespace detail {
2394 
2395 // Returns false if not a short option. Otherwise, sets opt name and rest and returns true
2396 inline bool split_short(const std::string &current, std::string &name, std::string &rest) {
2397  if(current.size() > 1 && current[0] == '-' && valid_first_char(current[1])) {
2398  name = current.substr(1, 1);
2399  rest = current.substr(2);
2400  return true;
2401  }
2402  return false;
2403 }
2404 
2405 // Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true
2406 inline bool split_long(const std::string &current, std::string &name, std::string &value) {
2407  if(current.size() > 2 && current.substr(0, 2) == "--" && valid_first_char(current[2])) {
2408  auto loc = current.find_first_of('=');
2409  if(loc != std::string::npos) {
2410  name = current.substr(2, loc - 2);
2411  value = current.substr(loc + 1);
2412  } else {
2413  name = current.substr(2);
2414  value = "";
2415  }
2416  return true;
2417  }
2418  return false;
2419 }
2420 
2421 // Returns false if not a windows style option. Otherwise, sets opt name and value and returns true
2422 inline bool split_windows_style(const std::string &current, std::string &name, std::string &value) {
2423  if(current.size() > 1 && current[0] == '/' && valid_first_char(current[1])) {
2424  auto loc = current.find_first_of(':');
2425  if(loc != std::string::npos) {
2426  name = current.substr(1, loc - 1);
2427  value = current.substr(loc + 1);
2428  } else {
2429  name = current.substr(1);
2430  value = "";
2431  }
2432  return true;
2433  }
2434  return false;
2435 }
2436 
2437 // Splits a string into multiple long and short names
2438 inline std::vector<std::string> split_names(std::string current) {
2439  std::vector<std::string> output;
2440  std::size_t val;
2441  while((val = current.find(",")) != std::string::npos) {
2442  output.push_back(trim_copy(current.substr(0, val)));
2443  current = current.substr(val + 1);
2444  }
2445  output.push_back(trim_copy(current));
2446  return output;
2447 }
2448 
2450 inline std::vector<std::pair<std::string, std::string>> get_default_flag_values(const std::string &str) {
2451  std::vector<std::string> flags = split_names(str);
2452  flags.erase(std::remove_if(flags.begin(),
2453  flags.end(),
2454  [](const std::string &name) {
2455  return ((name.empty()) || (!(((name.find_first_of('{') != std::string::npos) &&
2456  (name.back() == '}')) ||
2457  (name[0] == '!'))));
2458  }),
2459  flags.end());
2460  std::vector<std::pair<std::string, std::string>> output;
2461  output.reserve(flags.size());
2462  for(auto &flag : flags) {
2463  auto def_start = flag.find_first_of('{');
2464  std::string defval = "false";
2465  if((def_start != std::string::npos) && (flag.back() == '}')) {
2466  defval = flag.substr(def_start + 1);
2467  defval.pop_back();
2468  flag.erase(def_start, std::string::npos);
2469  }
2470  flag.erase(0, flag.find_first_not_of("-!"));
2471  output.emplace_back(flag, defval);
2472  }
2473  return output;
2474 }
2475 
2477 inline std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
2478 get_names(const std::vector<std::string> &input) {
2479 
2480  std::vector<std::string> short_names;
2481  std::vector<std::string> long_names;
2482  std::string pos_name;
2483 
2484  for(std::string name : input) {
2485  if(name.length() == 0) {
2486  continue;
2487  }
2488  if(name.length() > 1 && name[0] == '-' && name[1] != '-') {
2489  if(name.length() == 2 && valid_first_char(name[1]))
2490  short_names.emplace_back(1, name[1]);
2491  else
2492  throw BadNameString::OneCharName(name);
2493  } else if(name.length() > 2 && name.substr(0, 2) == "--") {
2494  name = name.substr(2);
2495  if(valid_name_string(name))
2496  long_names.push_back(name);
2497  else
2498  throw BadNameString::BadLongName(name);
2499  } else if(name == "-" || name == "--") {
2500  throw BadNameString::DashesOnly(name);
2501  } else {
2502  if(pos_name.length() > 0)
2503  throw BadNameString::MultiPositionalNames(name);
2504  pos_name = name;
2505  }
2506  }
2507 
2508  return std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>(
2509  short_names, long_names, pos_name);
2510 }
2511 
2512 } // namespace detail
2513 
2514 
2515 
2516 class App;
2517 
2519 struct ConfigItem {
2521  std::vector<std::string> parents{};
2522 
2524  std::string name{};
2525 
2527  std::vector<std::string> inputs{};
2528 
2530  std::string fullname() const {
2531  std::vector<std::string> tmp = parents;
2532  tmp.emplace_back(name);
2533  return detail::join(tmp, ".");
2534  }
2535 };
2536 
2538 class Config {
2539  protected:
2540  std::vector<ConfigItem> items{};
2541 
2542  public:
2544  virtual std::string to_config(const App *, bool, bool, std::string) const = 0;
2545 
2547  virtual std::vector<ConfigItem> from_config(std::istream &) const = 0;
2548 
2550  virtual std::string to_flag(const ConfigItem &item) const {
2551  if(item.inputs.size() == 1) {
2552  return item.inputs.at(0);
2553  }
2554  throw ConversionError::TooManyInputsFlag(item.fullname());
2555  }
2556 
2558  std::vector<ConfigItem> from_file(const std::string &name) {
2559  std::ifstream input{name};
2560  if(!input.good())
2561  throw FileError::Missing(name);
2562 
2563  return from_config(input);
2564  }
2565 
2567  virtual ~Config() = default;
2568 };
2569 
2571 class ConfigBase : public Config {
2572  protected:
2574  char commentChar = '#';
2576  char arrayStart = '[';
2578  char arrayEnd = ']';
2580  char arraySeparator = ',';
2582  char valueDelimiter = '=';
2584  char stringQuote = '"';
2586  char characterQuote = '\'';
2587 
2588  public:
2589  std::string
2590  to_config(const App * /*app*/, bool default_also, bool write_description, std::string prefix) const override;
2591 
2592  std::vector<ConfigItem> from_config(std::istream &input) const override;
2594  ConfigBase *comment(char cchar) {
2595  commentChar = cchar;
2596  return this;
2597  }
2599  ConfigBase *arrayBounds(char aStart, char aEnd) {
2600  arrayStart = aStart;
2601  arrayEnd = aEnd;
2602  return this;
2603  }
2606  arraySeparator = aSep;
2607  return this;
2608  }
2611  valueDelimiter = vSep;
2612  return this;
2613  }
2615  ConfigBase *quoteCharacter(char qString, char qChar) {
2616  stringQuote = qString;
2617  characterQuote = qChar;
2618  return this;
2619  }
2620 };
2621 
2623 using ConfigTOML = ConfigBase;
2624 
2626 class ConfigINI : public ConfigTOML {
2627 
2628  public:
2629  ConfigINI() {
2630  commentChar = ';';
2631  arrayStart = '\0';
2632  arrayEnd = '\0';
2633  arraySeparator = ' ';
2634  valueDelimiter = '=';
2635  }
2636 };
2637 
2638 
2639 
2640 class Option;
2641 
2643 
2650 
2652 class Validator {
2653  protected:
2655  std::function<std::string()> desc_function_{[]() { return std::string{}; }};
2656 
2659  std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
2661  std::string name_{};
2663  int application_index_ = -1;
2665  bool active_{true};
2667  bool non_modifying_{false};
2668 
2669  public:
2670  Validator() = default;
2672  explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
2674  Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
2675  : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
2676  name_(std::move(validator_name)) {}
2678  Validator &operation(std::function<std::string(std::string &)> op) {
2679  func_ = std::move(op);
2680  return *this;
2681  }
2684  std::string operator()(std::string &str) const {
2685  std::string retstring;
2686  if(active_) {
2687  if(non_modifying_) {
2688  std::string value = str;
2689  retstring = func_(value);
2690  } else {
2691  retstring = func_(str);
2692  }
2693  }
2694  return retstring;
2695  }
2696 
2699  std::string operator()(const std::string &str) const {
2700  std::string value = str;
2701  return (active_) ? func_(value) : std::string{};
2702  }
2703 
2705  Validator &description(std::string validator_desc) {
2706  desc_function_ = [validator_desc]() { return validator_desc; };
2707  return *this;
2708  }
2710  Validator description(std::string validator_desc) const {
2711  Validator newval(*this);
2712  newval.desc_function_ = [validator_desc]() { return validator_desc; };
2713  return newval;
2714  }
2716  std::string get_description() const {
2717  if(active_) {
2718  return desc_function_();
2719  }
2720  return std::string{};
2721  }
2723  Validator &name(std::string validator_name) {
2724  name_ = std::move(validator_name);
2725  return *this;
2726  }
2728  Validator name(std::string validator_name) const {
2729  Validator newval(*this);
2730  newval.name_ = std::move(validator_name);
2731  return newval;
2732  }
2734  const std::string &get_name() const { return name_; }
2736  Validator &active(bool active_val = true) {
2737  active_ = active_val;
2738  return *this;
2739  }
2741  Validator active(bool active_val = true) const {
2742  Validator newval(*this);
2743  newval.active_ = active_val;
2744  return newval;
2745  }
2746 
2748  Validator &non_modifying(bool no_modify = true) {
2749  non_modifying_ = no_modify;
2750  return *this;
2751  }
2753  Validator &application_index(int app_index) {
2754  application_index_ = app_index;
2755  return *this;
2756  }
2758  Validator application_index(int app_index) const {
2759  Validator newval(*this);
2760  newval.application_index_ = app_index;
2761  return newval;
2762  }
2764  int get_application_index() const { return application_index_; }
2766  bool get_active() const { return active_; }
2767 
2769  bool get_modifying() const { return !non_modifying_; }
2770 
2773  Validator operator&(const Validator &other) const {
2774  Validator newval;
2775 
2776  newval._merge_description(*this, other, " AND ");
2777 
2778  // Give references (will make a copy in lambda function)
2779  const std::function<std::string(std::string & filename)> &f1 = func_;
2780  const std::function<std::string(std::string & filename)> &f2 = other.func_;
2781 
2782  newval.func_ = [f1, f2](std::string &input) {
2783  std::string s1 = f1(input);
2784  std::string s2 = f2(input);
2785  if(!s1.empty() && !s2.empty())
2786  return std::string("(") + s1 + ") AND (" + s2 + ")";
2787  else
2788  return s1 + s2;
2789  };
2790 
2791  newval.active_ = (active_ & other.active_);
2792  newval.application_index_ = application_index_;
2793  return newval;
2794  }
2795 
2798  Validator operator|(const Validator &other) const {
2799  Validator newval;
2800 
2801  newval._merge_description(*this, other, " OR ");
2802 
2803  // Give references (will make a copy in lambda function)
2804  const std::function<std::string(std::string &)> &f1 = func_;
2805  const std::function<std::string(std::string &)> &f2 = other.func_;
2806 
2807  newval.func_ = [f1, f2](std::string &input) {
2808  std::string s1 = f1(input);
2809  std::string s2 = f2(input);
2810  if(s1.empty() || s2.empty())
2811  return std::string();
2812 
2813  return std::string("(") + s1 + ") OR (" + s2 + ")";
2814  };
2815  newval.active_ = (active_ & other.active_);
2816  newval.application_index_ = application_index_;
2817  return newval;
2818  }
2819 
2822  Validator newval;
2823  const std::function<std::string()> &dfunc1 = desc_function_;
2824  newval.desc_function_ = [dfunc1]() {
2825  auto str = dfunc1();
2826  return (!str.empty()) ? std::string("NOT ") + str : std::string{};
2827  };
2828  // Give references (will make a copy in lambda function)
2829  const std::function<std::string(std::string & res)> &f1 = func_;
2830 
2831  newval.func_ = [f1, dfunc1](std::string &test) -> std::string {
2832  std::string s1 = f1(test);
2833  if(s1.empty()) {
2834  return std::string("check ") + dfunc1() + " succeeded improperly";
2835  }
2836  return std::string{};
2837  };
2838  newval.active_ = active_;
2839  newval.application_index_ = application_index_;
2840  return newval;
2841  }
2842 
2843  private:
2844  void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger) {
2845 
2846  const std::function<std::string()> &dfunc1 = val1.desc_function_;
2847  const std::function<std::string()> &dfunc2 = val2.desc_function_;
2848 
2849  desc_function_ = [=]() {
2850  std::string f1 = dfunc1();
2851  std::string f2 = dfunc2();
2852  if((f1.empty()) || (f2.empty())) {
2853  return f1 + f2;
2854  }
2855  return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')';
2856  };
2857  }
2858 }; // namespace CLI
2859 
2861 class CustomValidator : public Validator {
2862  public:
2863 };
2864 // The implementation of the built in validators is using the Validator class;
2865 // the user is only expected to use the const (static) versions (since there's no setup).
2866 // Therefore, this is in detail.
2867 namespace detail {
2868 
2870 enum class path_type { nonexistent, file, directory };
2871 
2872 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
2873 inline path_type check_path(const char *file) noexcept {
2875  std::error_code ec;
2876  auto stat = std::filesystem::status(file, ec);
2877  if(ec) {
2878  return path_type::nonexistent;
2879  }
2880  switch(stat.type()) {
2881  case std::filesystem::file_type::none:
2882  case std::filesystem::file_type::not_found:
2883  return path_type::nonexistent;
2884  case std::filesystem::file_type::directory:
2885  return path_type::directory;
2886  case std::filesystem::file_type::symlink:
2887  case std::filesystem::file_type::block:
2888  case std::filesystem::file_type::character:
2889  case std::filesystem::file_type::fifo:
2890  case std::filesystem::file_type::socket:
2891  case std::filesystem::file_type::regular:
2892  case std::filesystem::file_type::unknown:
2893  default:
2894  return path_type::file;
2895  }
2896 }
2897 #else
2898 inline path_type check_path(const char *file) noexcept {
2900 #if defined(_MSC_VER)
2901  struct __stat64 buffer;
2902  if(_stat64(file, &buffer) == 0) {
2903  return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
2904  }
2905 #else
2906  struct stat buffer;
2907  if(stat(file, &buffer) == 0) {
2908  return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
2909  }
2910 #endif
2911  return path_type::nonexistent;
2912 }
2913 #endif
2914 class ExistingFileValidator : public Validator {
2916  public:
2917  ExistingFileValidator() : Validator("FILE") {
2918  func_ = [](std::string &filename) {
2919  auto path_result = check_path(filename.c_str());
2920  if(path_result == path_type::nonexistent) {
2921  return "File does not exist: " + filename;
2922  }
2923  if(path_result == path_type::directory) {
2924  return "File is actually a directory: " + filename;
2925  }
2926  return std::string();
2927  };
2928  }
2929 };
2930 
2933  public:
2935  func_ = [](std::string &filename) {
2936  auto path_result = check_path(filename.c_str());
2937  if(path_result == path_type::nonexistent) {
2938  return "Directory does not exist: " + filename;
2939  }
2940  if(path_result == path_type::file) {
2941  return "Directory is actually a file: " + filename;
2942  }
2943  return std::string();
2944  };
2945  }
2946 };
2947 
2950  public:
2951  ExistingPathValidator() : Validator("PATH(existing)") {
2952  func_ = [](std::string &filename) {
2953  auto path_result = check_path(filename.c_str());
2954  if(path_result == path_type::nonexistent) {
2955  return "Path does not exist: " + filename;
2956  }
2957  return std::string();
2958  };
2959  }
2960 };
2961 
2964  public:
2965  NonexistentPathValidator() : Validator("PATH(non-existing)") {
2966  func_ = [](std::string &filename) {
2967  auto path_result = check_path(filename.c_str());
2968  if(path_result != path_type::nonexistent) {
2969  return "Path already exists: " + filename;
2970  }
2971  return std::string();
2972  };
2973  }
2974 };
2975 
2977 class IPV4Validator : public Validator {
2978  public:
2979  IPV4Validator() : Validator("IPV4") {
2980  func_ = [](std::string &ip_addr) {
2981  auto result = CLI::detail::split(ip_addr, '.');
2982  if(result.size() != 4) {
2983  return std::string("Invalid IPV4 address must have four parts (") + ip_addr + ')';
2984  }
2985  int num;
2986  for(const auto &var : result) {
2987  bool retval = detail::lexical_cast(var, num);
2988  if(!retval) {
2989  return std::string("Failed parsing number (") + var + ')';
2990  }
2991  if(num < 0 || num > 255) {
2992  return std::string("Each IP number must be between 0 and 255 ") + var;
2993  }
2994  }
2995  return std::string();
2996  };
2997  }
2998 };
2999 
3000 } // namespace detail
3001 
3002 // Static is not needed here, because global const implies static.
3003 
3005 const detail::ExistingFileValidator ExistingFile;
3006 
3008 const detail::ExistingDirectoryValidator ExistingDirectory;
3009 
3011 const detail::ExistingPathValidator ExistingPath;
3012 
3014 const detail::NonexistentPathValidator NonexistentPath;
3015 
3017 const detail::IPV4Validator ValidIPV4;
3018 
3020 template <typename DesiredType> class TypeValidator : public Validator {
3021  public:
3022  explicit TypeValidator(const std::string &validator_name) : Validator(validator_name) {
3023  func_ = [](std::string &input_string) {
3024  auto val = DesiredType();
3025  if(!detail::lexical_cast(input_string, val)) {
3026  return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
3027  }
3028  return std::string();
3029  };
3030  }
3031  TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
3032 };
3033 
3035 const TypeValidator<double> Number("NUMBER");
3036 
3038 class Range : public Validator {
3039  public:
3044  template <typename T>
3045  Range(T min, T max, const std::string &validator_name = std::string{}) : Validator(validator_name) {
3046  if(validator_name.empty()) {
3047  std::stringstream out;
3048  out << detail::type_name<T>() << " in [" << min << " - " << max << "]";
3049  description(out.str());
3050  }
3051 
3052  func_ = [min, max](std::string &input) {
3053  T val;
3054  bool converted = detail::lexical_cast(input, val);
3055  if((!converted) || (val < min || val > max))
3056  return std::string("Value ") + input + " not in range " + std::to_string(min) + " to " +
3057  std::to_string(max);
3058 
3059  return std::string();
3060  };
3061  }
3062 
3064  template <typename T>
3065  explicit Range(T max, const std::string &validator_name = std::string{})
3066  : Range(static_cast<T>(0), max, validator_name) {}
3067 };
3068 
3070 const Range NonNegativeNumber(std::numeric_limits<double>::max(), "NONNEGATIVE");
3071 
3073 const Range PositiveNumber(std::numeric_limits<double>::min(), std::numeric_limits<double>::max(), "POSITIVE");
3074 
3076 class Bound : public Validator {
3077  public:
3082  template <typename T> Bound(T min, T max) {
3083  std::stringstream out;
3084  out << detail::type_name<T>() << " bounded to [" << min << " - " << max << "]";
3085  description(out.str());
3086 
3087  func_ = [min, max](std::string &input) {
3088  T val;
3089  bool converted = detail::lexical_cast(input, val);
3090  if(!converted) {
3091  return std::string("Value ") + input + " could not be converted";
3092  }
3093  if(val < min)
3094  input = detail::to_string(min);
3095  else if(val > max)
3096  input = detail::to_string(max);
3097 
3098  return std::string{};
3099  };
3100  }
3101 
3103  template <typename T> explicit Bound(T max) : Bound(static_cast<T>(0), max) {}
3104 };
3105 
3106 namespace detail {
3107 template <typename T,
3108  enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
3109 auto smart_deref(T value) -> decltype(*value) {
3110  return *value;
3111 }
3112 
3113 template <
3114  typename T,
3115  enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
3116 typename std::remove_reference<T>::type &smart_deref(T &value) {
3117  return value;
3118 }
3120 template <typename T> std::string generate_set(const T &set) {
3121  using element_t = typename detail::element_type<T>::type;
3122  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
3123  std::string out(1, '{');
3124  out.append(detail::join(
3125  detail::smart_deref(set),
3126  [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
3127  ","));
3128  out.push_back('}');
3129  return out;
3130 }
3131 
3133 template <typename T> std::string generate_map(const T &map, bool key_only = false) {
3134  using element_t = typename detail::element_type<T>::type;
3135  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
3136  std::string out(1, '{');
3137  out.append(detail::join(
3138  detail::smart_deref(map),
3139  [key_only](const iteration_type_t &v) {
3140  std::string res{detail::to_string(detail::pair_adaptor<element_t>::first(v))};
3141 
3142  if(!key_only) {
3143  res.append("->");
3144  res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
3145  }
3146  return res;
3147  },
3148  ","));
3149  out.push_back('}');
3150  return out;
3151 }
3152 
3153 template <typename C, typename V> struct has_find {
3154  template <typename CC, typename VV>
3155  static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
3156  template <typename, typename> static auto test(...) -> decltype(std::false_type());
3157 
3158  static const auto value = decltype(test<C, V>(0))::value;
3159  using type = std::integral_constant<bool, value>;
3160 };
3161 
3163 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
3164 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3165  using element_t = typename detail::element_type<T>::type;
3166  auto &setref = detail::smart_deref(set);
3167  auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
3168  return (detail::pair_adaptor<element_t>::first(v) == val);
3169  });
3170  return {(it != std::end(setref)), it};
3171 }
3172 
3174 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
3175 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3176  auto &setref = detail::smart_deref(set);
3177  auto it = setref.find(val);
3178  return {(it != std::end(setref)), it};
3179 }
3180 
3182 template <typename T, typename V>
3183 auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
3184  -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3185  using element_t = typename detail::element_type<T>::type;
3186  // do the potentially faster first search
3187  auto res = search(set, val);
3188  if((res.first) || (!(filter_function))) {
3189  return res;
3190  }
3191  // if we haven't found it do the longer linear search with all the element translations
3192  auto &setref = detail::smart_deref(set);
3193  auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
3195  a = filter_function(a);
3196  return (a == val);
3197  });
3198  return {(it != std::end(setref)), it};
3199 }
3200 
3201 // the following suggestion was made by Nikita Ofitserov(@himikof)
3202 // done in templates to prevent compiler warnings on negation of unsigned numbers
3203 
3205 template <typename T>
3206 inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
3207  if((a > 0) == (b > 0)) {
3208  return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
3209  } else {
3210  return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
3211  }
3212 }
3214 template <typename T>
3215 inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
3216  return ((std::numeric_limits<T>::max)() / a < b);
3217 }
3218 
3220 template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
3221  if(a == 0 || b == 0 || a == 1 || b == 1) {
3222  a *= b;
3223  return true;
3224  }
3225  if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
3226  return false;
3227  }
3228  if(overflowCheck(a, b)) {
3229  return false;
3230  }
3231  a *= b;
3232  return true;
3233 }
3234 
3236 template <typename T>
3237 typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
3238  T c = a * b;
3239  if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
3240  return false;
3241  }
3242  a = c;
3243  return true;
3244 }
3245 
3246 } // namespace detail
3248 class IsMember : public Validator {
3249  public:
3250  using filter_fn_t = std::function<std::string(std::string)>;
3251 
3253  template <typename T, typename... Args>
3254  IsMember(std::initializer_list<T> values, Args &&... args)
3255  : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
3256 
3258  template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
3259 
3262  template <typename T, typename F> explicit IsMember(T set, F filter_function) {
3263 
3264  // Get the type of the contained item - requires a container have ::value_type
3265  // if the type does not have first_type and second_type, these are both value_type
3266  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
3267  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
3268 
3269  using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
3270  // (const char * to std::string)
3271 
3272  // Make a local copy of the filter function, using a std::function if not one already
3273  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3274 
3275  // This is the type name for help, it will take the current version of the set contents
3276  desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
3277 
3278  // This is the function that validates
3279  // It stores a copy of the set pointer-like, so shared_ptr will stay alive
3280  func_ = [set, filter_fn](std::string &input) {
3281  local_item_t b;
3282  if(!detail::lexical_cast(input, b)) {
3283  throw ValidationError(input); // name is added later
3284  }
3285  if(filter_fn) {
3286  b = filter_fn(b);
3287  }
3288  auto res = detail::search(set, b, filter_fn);
3289  if(res.first) {
3290  // Make sure the version in the input string is identical to the one in the set
3291  if(filter_fn) {
3292  input = detail::value_string(detail::pair_adaptor<element_t>::first(*(res.second)));
3293  }
3294 
3295  // Return empty error string (success)
3296  return std::string{};
3297  }
3298 
3299  // If you reach this point, the result was not found
3300  return input + " not in " + detail::generate_set(detail::smart_deref(set));
3301  };
3302  }
3303 
3305  template <typename T, typename... Args>
3306  IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
3307  : IsMember(
3308  std::forward<T>(set),
3309  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
3310  other...) {}
3311 };
3312 
3314 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
3315 
3317 class Transformer : public Validator {
3318  public:
3319  using filter_fn_t = std::function<std::string(std::string)>;
3320 
3322  template <typename... Args>
3323  Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&... args)
3324  : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
3325 
3327  template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
3328 
3331  template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
3332 
3333  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
3334  "mapping must produce value pairs");
3335  // Get the type of the contained item - requires a container have ::value_type
3336  // if the type does not have first_type and second_type, these are both value_type
3337  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
3338  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
3339  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
3340  // (const char * to std::string)
3341 
3342  // Make a local copy of the filter function, using a std::function if not one already
3343  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3344 
3345  // This is the type name for help, it will take the current version of the set contents
3346  desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
3347 
3348  func_ = [mapping, filter_fn](std::string &input) {
3349  local_item_t b;
3350  if(!detail::lexical_cast(input, b)) {
3351  return std::string();
3352  // there is no possible way we can match anything in the mapping if we can't convert so just return
3353  }
3354  if(filter_fn) {
3355  b = filter_fn(b);
3356  }
3357  auto res = detail::search(mapping, b, filter_fn);
3358  if(res.first) {
3359  input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
3360  }
3361  return std::string{};
3362  };
3363  }
3364 
3366  template <typename T, typename... Args>
3367  Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
3368  : Transformer(
3369  std::forward<T>(mapping),
3370  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
3371  other...) {}
3372 };
3373 
3376  public:
3377  using filter_fn_t = std::function<std::string(std::string)>;
3378 
3380  template <typename... Args>
3381  CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&... args)
3382  : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
3383 
3385  template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
3386 
3389  template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
3390 
3391  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
3392  "mapping must produce value pairs");
3393  // Get the type of the contained item - requires a container have ::value_type
3394  // if the type does not have first_type and second_type, these are both value_type
3395  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
3396  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
3397  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
3398  // (const char * to std::string)
3399  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
3400 
3401  // Make a local copy of the filter function, using a std::function if not one already
3402  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3403 
3404  auto tfunc = [mapping]() {
3405  std::string out("value in ");
3406  out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
3407  out += detail::join(
3408  detail::smart_deref(mapping),
3409  [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
3410  ",");
3411  out.push_back('}');
3412  return out;
3413  };
3414 
3415  desc_function_ = tfunc;
3416 
3417  func_ = [mapping, tfunc, filter_fn](std::string &input) {
3418  local_item_t b;
3419  bool converted = detail::lexical_cast(input, b);
3420  if(converted) {
3421  if(filter_fn) {
3422  b = filter_fn(b);
3423  }
3424  auto res = detail::search(mapping, b, filter_fn);
3425  if(res.first) {
3426  input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
3427  return std::string{};
3428  }
3429  }
3430  for(const auto &v : detail::smart_deref(mapping)) {
3431  auto output_string = detail::value_string(detail::pair_adaptor<element_t>::second(v));
3432  if(output_string == input) {
3433  return std::string();
3434  }
3435  }
3436 
3437  return "Check " + input + " " + tfunc() + " FAILED";
3438  };
3439  }
3440 
3442  template <typename T, typename... Args>
3443  CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
3445  std::forward<T>(mapping),
3446  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
3447  other...) {}
3448 };
3449 
3451 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
3452 
3454 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
3455 
3457 inline std::string ignore_space(std::string item) {
3458  item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
3459  item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
3460  return item;
3461 }
3462 
3474 class AsNumberWithUnit : public Validator {
3475  public:
3480  enum Options {
3481  CASE_SENSITIVE = 0,
3482  CASE_INSENSITIVE = 1,
3483  UNIT_OPTIONAL = 0,
3484  UNIT_REQUIRED = 2,
3485  DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
3486  };
3487 
3488  template <typename Number>
3489  explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
3490  Options opts = DEFAULT,
3491  const std::string &unit_name = "UNIT") {
3492  description(generate_description<Number>(unit_name, opts));
3493  validate_mapping(mapping, opts);
3494 
3495  // transform function
3496  func_ = [mapping, opts](std::string &input) -> std::string {
3497  Number num;
3498 
3499  detail::rtrim(input);
3500  if(input.empty()) {
3501  throw ValidationError("Input is empty");
3502  }
3503 
3504  // Find split position between number and prefix
3505  auto unit_begin = input.end();
3506  while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
3507  --unit_begin;
3508  }
3509 
3510  std::string unit{unit_begin, input.end()};
3511  input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
3512  detail::trim(input);
3513 
3514  if(opts & UNIT_REQUIRED && unit.empty()) {
3515  throw ValidationError("Missing mandatory unit");
3516  }
3517  if(opts & CASE_INSENSITIVE) {
3518  unit = detail::to_lower(unit);
3519  }
3520  if(unit.empty()) {
3521  if(!detail::lexical_cast(input, num)) {
3522  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
3523  detail::type_name<Number>());
3524  }
3525  // No need to modify input if no unit passed
3526  return {};
3527  }
3528 
3529  // find corresponding factor
3530  auto it = mapping.find(unit);
3531  if(it == mapping.end()) {
3532  throw ValidationError(unit +
3533  " unit not recognized. "
3534  "Allowed values: " +
3535  detail::generate_map(mapping, true));
3536  }
3537 
3538  if(!input.empty()) {
3539  bool converted = detail::lexical_cast(input, num);
3540  if(!converted) {
3541  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
3542  detail::type_name<Number>());
3543  }
3544  // perform safe multiplication
3545  bool ok = detail::checked_multiply(num, it->second);
3546  if(!ok) {
3547  throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
3548  " factor would cause number overflow. Use smaller value.");
3549  }
3550  } else {
3551  num = static_cast<Number>(it->second);
3552  }
3553 
3554  input = detail::to_string(num);
3555 
3556  return {};
3557  };
3558  }
3559 
3560  private:
3563  template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
3564  for(auto &kv : mapping) {
3565  if(kv.first.empty()) {
3566  throw ValidationError("Unit must not be empty.");
3567  }
3568  if(!detail::isalpha(kv.first)) {
3569  throw ValidationError("Unit must contain only letters.");
3570  }
3571  }
3572 
3573  // make all units lowercase if CASE_INSENSITIVE
3574  if(opts & CASE_INSENSITIVE) {
3575  std::map<std::string, Number> lower_mapping;
3576  for(auto &kv : mapping) {
3577  auto s = detail::to_lower(kv.first);
3578  if(lower_mapping.count(s)) {
3579  throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
3580  s);
3581  }
3582  lower_mapping[detail::to_lower(kv.first)] = kv.second;
3583  }
3584  mapping = std::move(lower_mapping);
3585  }
3586  }
3587 
3589  template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
3590  std::stringstream out;
3591  out << detail::type_name<Number>() << ' ';
3592  if(opts & UNIT_REQUIRED) {
3593  out << name;
3594  } else {
3595  out << '[' << name << ']';
3596  }
3597  return out.str();
3598  }
3599 };
3600 
3613  public:
3614  using result_t = std::uint64_t;
3615 
3623  explicit AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) {
3624  if(kb_is_1000) {
3625  description("SIZE [b, kb(=1000b), kib(=1024b), ...]");
3626  } else {
3627  description("SIZE [b, kb(=1024b), ...]");
3628  }
3629  }
3630 
3631  private:
3633  static std::map<std::string, result_t> init_mapping(bool kb_is_1000) {
3634  std::map<std::string, result_t> m;
3635  result_t k_factor = kb_is_1000 ? 1000 : 1024;
3636  result_t ki_factor = 1024;
3637  result_t k = 1;
3638  result_t ki = 1;
3639  m["b"] = 1;
3640  for(std::string p : {"k", "m", "g", "t", "p", "e"}) {
3641  k *= k_factor;
3642  ki *= ki_factor;
3643  m[p] = k;
3644  m[p + "b"] = k;
3645  m[p + "i"] = ki;
3646  m[p + "ib"] = ki;
3647  }
3648  return m;
3649  }
3650 
3652  static std::map<std::string, result_t> get_mapping(bool kb_is_1000) {
3653  if(kb_is_1000) {
3654  static auto m = init_mapping(true);
3655  return m;
3656  } else {
3657  static auto m = init_mapping(false);
3658  return m;
3659  }
3660  }
3661 };
3662 
3663 namespace detail {
3668 inline std::pair<std::string, std::string> split_program_name(std::string commandline) {
3669  // try to determine the programName
3670  std::pair<std::string, std::string> vals;
3671  trim(commandline);
3672  auto esp = commandline.find_first_of(' ', 1);
3673  while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
3674  esp = commandline.find_first_of(' ', esp + 1);
3675  if(esp == std::string::npos) {
3676  // if we have reached the end and haven't found a valid file just assume the first argument is the
3677  // program name
3678  if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') {
3679  bool embeddedQuote = false;
3680  auto keyChar = commandline[0];
3681  auto end = commandline.find_first_of(keyChar, 1);
3682  while((end != std::string::npos) && (commandline[end - 1] == '\\')) { // deal with escaped quotes
3683  end = commandline.find_first_of(keyChar, end + 1);
3684  embeddedQuote = true;
3685  }
3686  if(end != std::string::npos) {
3687  vals.first = commandline.substr(1, end - 1);
3688  esp = end + 1;
3689  if(embeddedQuote) {
3690  vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar));
3691  embeddedQuote = false;
3692  }
3693  } else {
3694  esp = commandline.find_first_of(' ', 1);
3695  }
3696  } else {
3697  esp = commandline.find_first_of(' ', 1);
3698  }
3699 
3700  break;
3701  }
3702  }
3703  if(vals.first.empty()) {
3704  vals.first = commandline.substr(0, esp);
3705  rtrim(vals.first);
3706  }
3707 
3708  // strip the program name
3709  vals.second = (esp != std::string::npos) ? commandline.substr(esp + 1) : std::string{};
3710  ltrim(vals.second);
3711  return vals;
3712 }
3713 
3714 } // namespace detail
3716 
3717 
3718 
3719 
3720 class Option;
3721 class App;
3722 
3727 
3728 enum class AppFormatMode {
3729  Normal,
3730  All,
3731  Sub,
3732 };
3733 
3739  protected:
3742 
3744  std::size_t column_width_{30};
3745 
3748  std::map<std::string, std::string> labels_{};
3749 
3753 
3754  public:
3755  FormatterBase() = default;
3756  FormatterBase(const FormatterBase &) = default;
3757  FormatterBase(FormatterBase &&) = default;
3758 
3760  virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default)
3761 
3763  virtual std::string make_help(const App *, std::string, AppFormatMode) const = 0;
3764 
3768 
3770  void label(std::string key, std::string val) { labels_[key] = val; }
3771 
3773  void column_width(std::size_t val) { column_width_ = val; }
3774 
3778 
3780  std::string get_label(std::string key) const {
3781  if(labels_.find(key) == labels_.end())
3782  return key;
3783  else
3784  return labels_.at(key);
3785  }
3786 
3788  std::size_t get_column_width() const { return column_width_; }
3789 
3791 };
3792 
3794 class FormatterLambda final : public FormatterBase {
3795  using funct_t = std::function<std::string(const App *, std::string, AppFormatMode)>;
3796 
3798  funct_t lambda_;
3799 
3800  public:
3802  explicit FormatterLambda(funct_t funct) : lambda_(std::move(funct)) {}
3803 
3805  ~FormatterLambda() noexcept override {} // NOLINT(modernize-use-equals-default)
3806 
3808  std::string make_help(const App *app, std::string name, AppFormatMode mode) const override {
3809  return lambda_(app, name, mode);
3810  }
3811 };
3812 
3815 class Formatter : public FormatterBase {
3816  public:
3817  Formatter() = default;
3818  Formatter(const Formatter &) = default;
3819  Formatter(Formatter &&) = default;
3820 
3823 
3826  virtual std::string make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const;
3827 
3829  virtual std::string make_positionals(const App *app) const;
3830 
3832  std::string make_groups(const App *app, AppFormatMode mode) const;
3833 
3835  virtual std::string make_subcommands(const App *app, AppFormatMode mode) const;
3836 
3838  virtual std::string make_subcommand(const App *sub) const;
3839 
3841  virtual std::string make_expanded(const App *sub) const;
3842 
3844  virtual std::string make_footer(const App *app) const;
3845 
3847  virtual std::string make_description(const App *app) const;
3848 
3850  virtual std::string make_usage(const App *app, std::string name) const;
3851 
3853  std::string make_help(const App * /*app*/, std::string, AppFormatMode) const override;
3854 
3858 
3860  virtual std::string make_option(const Option *opt, bool is_positional) const {
3861  std::stringstream out;
3862  detail::format_help(
3863  out, make_option_name(opt, is_positional) + make_option_opts(opt), make_option_desc(opt), column_width_);
3864  return out.str();
3865  }
3866 
3868  virtual std::string make_option_name(const Option *, bool) const;
3869 
3871  virtual std::string make_option_opts(const Option *) const;
3872 
3874  virtual std::string make_option_desc(const Option *) const;
3875 
3877  virtual std::string make_option_usage(const Option *opt) const;
3878 
3880 };
3881 
3882 
3883 
3884 
3885 using results_t = std::vector<std::string>;
3887 using callback_t = std::function<bool(const results_t &)>;
3888 
3889 class Option;
3890 class App;
3891 
3892 using Option_p = std::unique_ptr<Option>;
3894 enum class MultiOptionPolicy : char {
3895  Throw,
3896  TakeLast,
3897  TakeFirst,
3898  Join,
3899  TakeAll
3900 };
3901 
3904 template <typename CRTP> class OptionBase {
3905  friend App;
3906 
3907  protected:
3909  std::string group_ = std::string("Options");
3910 
3912  bool required_{false};
3913 
3915  bool ignore_case_{false};
3916 
3918  bool ignore_underscore_{false};
3919 
3921  bool configurable_{true};
3922 
3924  bool disable_flag_override_{false};
3925 
3927  char delimiter_{'\0'};
3928 
3930  bool always_capture_default_{false};
3931 
3933  MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
3934 
3936  template <typename T> void copy_to(T *other) const {
3937  other->group(group_);
3938  other->required(required_);
3939  other->ignore_case(ignore_case_);
3940  other->ignore_underscore(ignore_underscore_);
3941  other->configurable(configurable_);
3942  other->disable_flag_override(disable_flag_override_);
3943  other->delimiter(delimiter_);
3944  other->always_capture_default(always_capture_default_);
3945  other->multi_option_policy(multi_option_policy_);
3946  }
3947 
3948  public:
3949  // setters
3950 
3952  CRTP *group(const std::string &name) {
3953  group_ = name;
3954  return static_cast<CRTP *>(this);
3955  }
3956 
3958  CRTP *required(bool value = true) {
3959  required_ = value;
3960  return static_cast<CRTP *>(this);
3961  }
3962 
3964  CRTP *mandatory(bool value = true) { return required(value); }
3965 
3966  CRTP *always_capture_default(bool value = true) {
3967  always_capture_default_ = value;
3968  return static_cast<CRTP *>(this);
3969  }
3970 
3971  // Getters
3972 
3974  const std::string &get_group() const { return group_; }
3975 
3977  bool get_required() const { return required_; }
3978 
3980  bool get_ignore_case() const { return ignore_case_; }
3981 
3983  bool get_ignore_underscore() const { return ignore_underscore_; }
3984 
3986  bool get_configurable() const { return configurable_; }
3987 
3989  bool get_disable_flag_override() const { return disable_flag_override_; }
3990 
3992  char get_delimiter() const { return delimiter_; }
3993 
3995  bool get_always_capture_default() const { return always_capture_default_; }
3996 
3998  MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
3999 
4000  // Shortcuts for multi option policy
4001 
4003  CRTP *take_last() {
4004  auto self = static_cast<CRTP *>(this);
4005  self->multi_option_policy(MultiOptionPolicy::TakeLast);
4006  return self;
4007  }
4008 
4010  CRTP *take_first() {
4011  auto self = static_cast<CRTP *>(this);
4012  self->multi_option_policy(MultiOptionPolicy::TakeFirst);
4013  return self;
4014  }
4015 
4017  CRTP *take_all() {
4018  auto self = static_cast<CRTP *>(this);
4019  self->multi_option_policy(MultiOptionPolicy::TakeAll);
4020  return self;
4021  }
4022 
4024  CRTP *join() {
4025  auto self = static_cast<CRTP *>(this);
4026  self->multi_option_policy(MultiOptionPolicy::Join);
4027  return self;
4028  }
4029 
4031  CRTP *join(char delim) {
4032  auto self = static_cast<CRTP *>(this);
4033  self->delimiter_ = delim;
4034  self->multi_option_policy(MultiOptionPolicy::Join);
4035  return self;
4036  }
4037 
4039  CRTP *configurable(bool value = true) {
4040  configurable_ = value;
4041  return static_cast<CRTP *>(this);
4042  }
4043 
4045  CRTP *delimiter(char value = '\0') {
4046  delimiter_ = value;
4047  return static_cast<CRTP *>(this);
4048  }
4049 };
4050 
4053 class OptionDefaults : public OptionBase<OptionDefaults> {
4054  public:
4055  OptionDefaults() = default;
4056 
4057  // Methods here need a different implementation if they are Option vs. OptionDefault
4058 
4060  OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
4061  multi_option_policy_ = value;
4062  return this;
4063  }
4064 
4066  OptionDefaults *ignore_case(bool value = true) {
4067  ignore_case_ = value;
4068  return this;
4069  }
4070 
4072  OptionDefaults *ignore_underscore(bool value = true) {
4073  ignore_underscore_ = value;
4074  return this;
4075  }
4076 
4079  disable_flag_override_ = value;
4080  return this;
4081  }
4082 
4084  OptionDefaults *delimiter(char value = '\0') {
4085  delimiter_ = value;
4086  return this;
4087  }
4088 };
4089 
4090 class Option : public OptionBase<Option> {
4091  friend App;
4092 
4093  protected:
4096 
4098  std::vector<std::string> snames_{};
4099 
4101  std::vector<std::string> lnames_{};
4102 
4105  std::vector<std::pair<std::string, std::string>> default_flag_values_{};
4106 
4108  std::vector<std::string> fnames_{};
4109 
4111  std::string pname_{};
4112 
4114  std::string envname_{};
4115 
4119 
4121  std::string description_{};
4122 
4124  std::string default_str_{};
4125 
4127  std::string option_text_{};
4128 
4132  std::function<std::string()> type_name_{[]() { return std::string(); }};
4133 
4135  std::function<std::string()> default_function_{};
4136 
4140 
4143  int type_size_max_{1};
4145  int type_size_min_{1};
4146 
4148  int expected_min_{1};
4150  int expected_max_{1};
4151 
4153  std::vector<Validator> validators_{};
4154 
4156  std::set<Option *> needs_{};
4157 
4159  std::set<Option *> excludes_{};
4160 
4164 
4166  App *parent_{nullptr};
4167 
4169  callback_t callback_{};
4170 
4174 
4176  results_t results_{};
4178  results_t proc_results_{};
4180  enum class option_state : char {
4181  parsing = 0,
4182  validated = 2,
4183  reduced = 4,
4184  callback_run = 6,
4185  };
4187  option_state current_option_state_{option_state::parsing};
4189  bool allow_extra_args_{false};
4191  bool flag_like_{false};
4193  bool run_callback_for_default_{false};
4195  bool inject_separator_{false};
4197 
4199  Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
4200  : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
4201  std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name));
4202  }
4203 
4204  public:
4207 
4208  Option(const Option &) = delete;
4209  Option &operator=(const Option &) = delete;
4210 
4212  std::size_t count() const { return results_.size(); }
4213 
4215  bool empty() const { return results_.empty(); }
4216 
4218  explicit operator bool() const { return !empty(); }
4219 
4221  void clear() {
4222  results_.clear();
4223  current_option_state_ = option_state::parsing;
4224  }
4225 
4229 
4231  Option *expected(int value) {
4232  if(value < 0) {
4233  expected_min_ = -value;
4234  if(expected_max_ < expected_min_) {
4235  expected_max_ = expected_min_;
4236  }
4237  allow_extra_args_ = true;
4238  flag_like_ = false;
4239  } else if(value == detail::expected_max_vector_size) {
4240  expected_min_ = 1;
4241  expected_max_ = detail::expected_max_vector_size;
4242  allow_extra_args_ = true;
4243  flag_like_ = false;
4244  } else {
4245  expected_min_ = value;
4246  expected_max_ = value;
4247  flag_like_ = (expected_min_ == 0);
4248  }
4249  return this;
4250  }
4251 
4253  Option *expected(int value_min, int value_max) {
4254  if(value_min < 0) {
4255  value_min = -value_min;
4256  }
4257 
4258  if(value_max < 0) {
4259  value_max = detail::expected_max_vector_size;
4260  }
4261  if(value_max < value_min) {
4262  expected_min_ = value_max;
4263  expected_max_ = value_min;
4264  } else {
4265  expected_max_ = value_max;
4266  expected_min_ = value_min;
4267  }
4268 
4269  return this;
4270  }
4273  Option *allow_extra_args(bool value = true) {
4274  allow_extra_args_ = value;
4275  return this;
4276  }
4278  bool get_allow_extra_args() const { return allow_extra_args_; }
4279 
4282  Option *run_callback_for_default(bool value = true) {
4283  run_callback_for_default_ = value;
4284  return this;
4285  }
4287  bool get_run_callback_for_default() const { return run_callback_for_default_; }
4288 
4290  Option *check(Validator validator, const std::string &validator_name = "") {
4291  validator.non_modifying();
4292  validators_.push_back(std::move(validator));
4293  if(!validator_name.empty())
4294  validators_.back().name(validator_name);
4295  return this;
4296  }
4297 
4299  Option *check(std::function<std::string(const std::string &)> Validator,
4300  std::string Validator_description = "",
4301  std::string Validator_name = "") {
4302  validators_.emplace_back(Validator, std::move(Validator_description), std::move(Validator_name));
4303  validators_.back().non_modifying();
4304  return this;
4305  }
4306 
4308  Option *transform(Validator Validator, const std::string &Validator_name = "") {
4309  validators_.insert(validators_.begin(), std::move(Validator));
4310  if(!Validator_name.empty())
4311  validators_.front().name(Validator_name);
4312  return this;
4313  }
4314 
4316  Option *transform(const std::function<std::string(std::string)> &func,
4317  std::string transform_description = "",
4318  std::string transform_name = "") {
4319  validators_.insert(validators_.begin(),
4320  Validator(
4321  [func](std::string &val) {
4322  val = func(val);
4323  return std::string{};
4324  },
4325  std::move(transform_description),
4326  std::move(transform_name)));
4327 
4328  return this;
4329  }
4330 
4332  Option *each(const std::function<void(std::string)> &func) {
4333  validators_.emplace_back(
4334  [func](std::string &inout) {
4335  func(inout);
4336  return std::string{};
4337  },
4338  std::string{});
4339  return this;
4340  }
4342  Validator *get_validator(const std::string &Validator_name = "") {
4343  for(auto &Validator : validators_) {
4344  if(Validator_name == Validator.get_name()) {
4345  return &Validator;
4346  }
4347  }
4348  if((Validator_name.empty()) && (!validators_.empty())) {
4349  return &(validators_.front());
4350  }
4351  throw OptionNotFound(std::string{"Validator "} + Validator_name + " Not Found");
4352  }
4353 
4355  Validator *get_validator(int index) {
4356  // This is an signed int so that it is not equivalent to a pointer.
4357  if(index >= 0 && index < static_cast<int>(validators_.size())) {
4358  return &(validators_[static_cast<decltype(validators_)::size_type>(index)]);
4359  }
4360  throw OptionNotFound("Validator index is not valid");
4361  }
4362 
4365  if(opt != this) {
4366  needs_.insert(opt);
4367  }
4368  return this;
4369  }
4370 
4372  template <typename T = App> Option *needs(std::string opt_name) {
4373  auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
4374  if(opt == nullptr) {
4375  throw IncorrectConstruction::MissingOption(opt_name);
4376  }
4377  return needs(opt);
4378  }
4379 
4381  template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
4382  needs(opt);
4383  return needs(opt1, args...);
4384  }
4385 
4387  bool remove_needs(Option *opt) {
4388  auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
4389 
4390  if(iterator == std::end(needs_)) {
4391  return false;
4392  }
4393  needs_.erase(iterator);
4394  return true;
4395  }
4396 
4399  if(opt == this) {
4400  throw(IncorrectConstruction("and option cannot exclude itself"));
4401  }
4402  excludes_.insert(opt);
4403 
4404  // Help text should be symmetric - excluding a should exclude b
4405  opt->excludes_.insert(this);
4406 
4407  // Ignoring the insert return value, excluding twice is now allowed.
4408  // (Mostly to allow both directions to be excluded by user, even though the library does it for you.)
4409 
4410  return this;
4411  }
4412 
4414  template <typename T = App> Option *excludes(std::string opt_name) {
4415  auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
4416  if(opt == nullptr) {
4417  throw IncorrectConstruction::MissingOption(opt_name);
4418  }
4419  return excludes(opt);
4420  }
4421 
4423  template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
4424  excludes(opt);
4425  return excludes(opt1, args...);
4426  }
4427 
4430  auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
4431 
4432  if(iterator == std::end(excludes_)) {
4433  return false;
4434  }
4435  excludes_.erase(iterator);
4436  return true;
4437  }
4438 
4440  Option *envname(std::string name) {
4441  envname_ = std::move(name);
4442  return this;
4443  }
4444 
4449  template <typename T = App> Option *ignore_case(bool value = true) {
4450  if(!ignore_case_ && value) {
4451  ignore_case_ = value;
4452  auto *parent = static_cast<T *>(parent_);
4453  for(const Option_p &opt : parent->options_) {
4454  if(opt.get() == this) {
4455  continue;
4456  }
4457  auto &omatch = opt->matching_name(*this);
4458  if(!omatch.empty()) {
4459  ignore_case_ = false;
4460  throw OptionAlreadyAdded("adding ignore case caused a name conflict with " + omatch);
4461  }
4462  }
4463  } else {
4464  ignore_case_ = value;
4465  }
4466  return this;
4467  }
4468 
4473  template <typename T = App> Option *ignore_underscore(bool value = true) {
4474 
4475  if(!ignore_underscore_ && value) {
4476  ignore_underscore_ = value;
4477  auto *parent = static_cast<T *>(parent_);
4478  for(const Option_p &opt : parent->options_) {
4479  if(opt.get() == this) {
4480  continue;
4481  }
4482  auto &omatch = opt->matching_name(*this);
4483  if(!omatch.empty()) {
4484  ignore_underscore_ = false;
4485  throw OptionAlreadyAdded("adding ignore underscore caused a name conflict with " + omatch);
4486  }
4487  }
4488  } else {
4489  ignore_underscore_ = value;
4490  }
4491  return this;
4492  }
4493 
4495  Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
4496  if(value != multi_option_policy_) {
4497  if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size &&
4498  expected_min_ > 1) { // this bizarre condition is to maintain backwards compatibility
4499  // with the previous behavior of expected_ with vectors
4500  expected_max_ = expected_min_;
4501  }
4502  multi_option_policy_ = value;
4503  current_option_state_ = option_state::parsing;
4504  }
4505  return this;
4506  }
4507 
4509  Option *disable_flag_override(bool value = true) {
4510  disable_flag_override_ = value;
4511  return this;
4512  }
4516 
4518  int get_type_size() const { return type_size_min_; }
4519 
4521  int get_type_size_min() const { return type_size_min_; }
4523  int get_type_size_max() const { return type_size_max_; }
4524 
4526  int get_inject_separator() const { return inject_separator_; }
4527 
4529  std::string get_envname() const { return envname_; }
4530 
4532  std::set<Option *> get_needs() const { return needs_; }
4533 
4535  std::set<Option *> get_excludes() const { return excludes_; }
4536 
4538  std::string get_default_str() const { return default_str_; }
4539 
4541  callback_t get_callback() const { return callback_; }
4542 
4544  const std::vector<std::string> &get_lnames() const { return lnames_; }
4545 
4547  const std::vector<std::string> &get_snames() const { return snames_; }
4548 
4550  const std::vector<std::string> &get_fnames() const { return fnames_; }
4552  const std::string &get_single_name() const {
4553  if(!lnames_.empty()) {
4554  return lnames_[0];
4555  }
4556  if(!pname_.empty()) {
4557  return pname_;
4558  }
4559  if(!snames_.empty()) {
4560  return snames_[0];
4561  }
4562  return envname_;
4563  }
4565  int get_expected() const { return expected_min_; }
4566 
4568  int get_expected_min() const { return expected_min_; }
4570  int get_expected_max() const { return expected_max_; }
4571 
4573  int get_items_expected_min() const { return type_size_min_ * expected_min_; }
4574 
4577  int t = type_size_max_;
4578  return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
4579  }
4581  int get_items_expected() const { return get_items_expected_min(); }
4582 
4584  bool get_positional() const { return pname_.length() > 0; }
4585 
4587  bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; }
4588 
4590  bool has_description() const { return description_.length() > 0; }
4591 
4593  const std::string &get_description() const { return description_; }
4594 
4596  Option *description(std::string option_description) {
4597  description_ = std::move(option_description);
4598  return this;
4599  }
4600 
4601  Option *option_text(std::string text) {
4602  option_text_ = std::move(text);
4603  return this;
4604  }
4605 
4606  const std::string &get_option_text() const { return option_text_; }
4607 
4611 
4616  std::string get_name(bool positional = false,
4617  bool all_options = false
4618  ) const {
4619  if(get_group().empty())
4620  return {}; // Hidden
4621 
4622  if(all_options) {
4623 
4624  std::vector<std::string> name_list;
4625 
4627  if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) {
4628  name_list.push_back(pname_);
4629  }
4630  if((get_items_expected() == 0) && (!fnames_.empty())) {
4631  for(const std::string &sname : snames_) {
4632  name_list.push_back("-" + sname);
4633  if(check_fname(sname)) {
4634  name_list.back() += "{" + get_flag_value(sname, "") + "}";
4635  }
4636  }
4637 
4638  for(const std::string &lname : lnames_) {
4639  name_list.push_back("--" + lname);
4640  if(check_fname(lname)) {
4641  name_list.back() += "{" + get_flag_value(lname, "") + "}";
4642  }
4643  }
4644  } else {
4645  for(const std::string &sname : snames_)
4646  name_list.push_back("-" + sname);
4647 
4648  for(const std::string &lname : lnames_)
4649  name_list.push_back("--" + lname);
4650  }
4651 
4652  return detail::join(name_list);
4653  }
4654 
4655  // This returns the positional name no matter what
4656  if(positional)
4657  return pname_;
4658 
4659  // Prefer long name
4660  if(!lnames_.empty())
4661  return std::string(2, '-') + lnames_[0];
4662 
4663  // Or short name if no long name
4664  if(!snames_.empty())
4665  return std::string(1, '-') + snames_[0];
4666 
4667  // If positional is the only name, it's okay to use that
4668  return pname_;
4669  }
4670 
4674 
4676  void run_callback() {
4677 
4678  if(current_option_state_ == option_state::parsing) {
4679  _validate_results(results_);
4680  current_option_state_ = option_state::validated;
4681  }
4682 
4683  if(current_option_state_ < option_state::reduced) {
4684  _reduce_results(proc_results_, results_);
4685  current_option_state_ = option_state::reduced;
4686  }
4687  if(current_option_state_ >= option_state::reduced) {
4688  current_option_state_ = option_state::callback_run;
4689  if(!(callback_)) {
4690  return;
4691  }
4692  const results_t &send_results = proc_results_.empty() ? results_ : proc_results_;
4693  bool local_result = callback_(send_results);
4694 
4695  if(!local_result)
4696  throw ConversionError(get_name(), results_);
4697  }
4698  }
4699 
4701  const std::string &matching_name(const Option &other) const {
4702  static const std::string estring;
4703  for(const std::string &sname : snames_)
4704  if(other.check_sname(sname))
4705  return sname;
4706  for(const std::string &lname : lnames_)
4707  if(other.check_lname(lname))
4708  return lname;
4709 
4710  if(ignore_case_ ||
4711  ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
4712  for(const std::string &sname : other.snames_)
4713  if(check_sname(sname))
4714  return sname;
4715  for(const std::string &lname : other.lnames_)
4716  if(check_lname(lname))
4717  return lname;
4718  }
4719  return estring;
4720  }
4722  bool operator==(const Option &other) const { return !matching_name(other).empty(); }
4723 
4725  bool check_name(const std::string &name) const {
4726 
4727  if(name.length() > 2 && name[0] == '-' && name[1] == '-')
4728  return check_lname(name.substr(2));
4729  if(name.length() > 1 && name.front() == '-')
4730  return check_sname(name.substr(1));
4731  if(!pname_.empty()) {
4732  std::string local_pname = pname_;
4733  std::string local_name = name;
4734  if(ignore_underscore_) {
4735  local_pname = detail::remove_underscore(local_pname);
4736  local_name = detail::remove_underscore(local_name);
4737  }
4738  if(ignore_case_) {
4739  local_pname = detail::to_lower(local_pname);
4740  local_name = detail::to_lower(local_name);
4741  }
4742  if(local_name == local_pname) {
4743  return true;
4744  }
4745  }
4746 
4747  if(!envname_.empty()) {
4748  // this needs to be the original since envname_ shouldn't match on case insensitivity
4749  return (name == envname_);
4750  }
4751  return false;
4752  }
4753 
4755  bool check_sname(std::string name) const {
4756  return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
4757  }
4758 
4760  bool check_lname(std::string name) const {
4761  return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
4762  }
4763 
4765  bool check_fname(std::string name) const {
4766  if(fnames_.empty()) {
4767  return false;
4768  }
4769  return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
4770  }
4771 
4774  std::string get_flag_value(const std::string &name, std::string input_value) const {
4775  static const std::string trueString{"true"};
4776  static const std::string falseString{"false"};
4777  static const std::string emptyString{"{}"};
4778  // check for disable flag override_
4779  if(disable_flag_override_) {
4780  if(!((input_value.empty()) || (input_value == emptyString))) {
4781  auto default_ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
4782  if(default_ind >= 0) {
4783  // We can static cast this to std::size_t because it is more than 0 in this block
4784  if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
4785  throw(ArgumentMismatch::FlagOverride(name));
4786  }
4787  } else {
4788  if(input_value != trueString) {
4789  throw(ArgumentMismatch::FlagOverride(name));
4790  }
4791  }
4792  }
4793  }
4794  auto ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
4795  if((input_value.empty()) || (input_value == emptyString)) {
4796  if(flag_like_) {
4797  return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second;
4798  } else {
4799  return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second;
4800  }
4801  }
4802  if(ind < 0) {
4803  return input_value;
4804  }
4805  if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) {
4806  try {
4807  auto val = detail::to_flag_value(input_value);
4808  return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
4809  } catch(const std::invalid_argument &) {
4810  return input_value;
4811  }
4812  } else {
4813  return input_value;
4814  }
4815  }
4816 
4818  Option *add_result(std::string s) {
4819  _add_result(std::move(s), results_);
4820  current_option_state_ = option_state::parsing;
4821  return this;
4822  }
4823 
4825  Option *add_result(std::string s, int &results_added) {
4826  results_added = _add_result(std::move(s), results_);
4827  current_option_state_ = option_state::parsing;
4828  return this;
4829  }
4830 
4832  Option *add_result(std::vector<std::string> s) {
4833  for(auto &str : s) {
4834  _add_result(std::move(str), results_);
4835  }
4836  current_option_state_ = option_state::parsing;
4837  return this;
4838  }
4839 
4841  const results_t &results() const { return results_; }
4842 
4844  results_t reduced_results() const {
4845  results_t res = proc_results_.empty() ? results_ : proc_results_;
4846  if(current_option_state_ < option_state::reduced) {
4847  if(current_option_state_ == option_state::parsing) {
4848  res = results_;
4849  _validate_results(res);
4850  }
4851  if(!res.empty()) {
4852  results_t extra;
4853  _reduce_results(extra, res);
4854  if(!extra.empty()) {
4855  res = std::move(extra);
4856  }
4857  }
4858  }
4859  return res;
4860  }
4861 
4863  template <typename T> void results(T &output) const {
4864  bool retval;
4865  if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
4866  const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
4867  retval = detail::lexical_conversion<T, T>(res, output);
4868  } else {
4869  results_t res;
4870  if(results_.empty()) {
4871  if(!default_str_.empty()) {
4872  // _add_results takes an rvalue only
4873  _add_result(std::string(default_str_), res);
4874  _validate_results(res);
4875  results_t extra;
4876  _reduce_results(extra, res);
4877  if(!extra.empty()) {
4878  res = std::move(extra);
4879  }
4880  } else {
4881  res.emplace_back();
4882  }
4883  } else {
4884  res = reduced_results();
4885  }
4886  retval = detail::lexical_conversion<T, T>(res, output);
4887  }
4888  if(!retval) {
4889  throw ConversionError(get_name(), results_);
4890  }
4891  }
4892 
4894  template <typename T> T as() const {
4895  T output;
4896  results(output);
4897  return output;
4898  }
4899 
4901  bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); }
4902 
4906 
4908  Option *type_name_fn(std::function<std::string()> typefun) {
4909  type_name_ = std::move(typefun);
4910  return this;
4911  }
4912 
4914  Option *type_name(std::string typeval) {
4915  type_name_fn([typeval]() { return typeval; });
4916  return this;
4917  }
4918 
4920  Option *type_size(int option_type_size) {
4921  if(option_type_size < 0) {
4922  // this section is included for backwards compatibility
4923  type_size_max_ = -option_type_size;
4924  type_size_min_ = -option_type_size;
4925  expected_max_ = detail::expected_max_vector_size;
4926  } else {
4927  type_size_max_ = option_type_size;
4928  if(type_size_max_ < detail::expected_max_vector_size) {
4929  type_size_min_ = option_type_size;
4930  } else {
4931  inject_separator_ = true;
4932  }
4933  if(type_size_max_ == 0)
4934  required_ = false;
4935  }
4936  return this;
4937  }
4939  Option *type_size(int option_type_size_min, int option_type_size_max) {
4940  if(option_type_size_min < 0 || option_type_size_max < 0) {
4941  // this section is included for backwards compatibility
4942  expected_max_ = detail::expected_max_vector_size;
4943  option_type_size_min = (std::abs)(option_type_size_min);
4944  option_type_size_max = (std::abs)(option_type_size_max);
4945  }
4946 
4947  if(option_type_size_min > option_type_size_max) {
4948  type_size_max_ = option_type_size_min;
4949  type_size_min_ = option_type_size_max;
4950  } else {
4951  type_size_min_ = option_type_size_min;
4952  type_size_max_ = option_type_size_max;
4953  }
4954  if(type_size_max_ == 0) {
4955  required_ = false;
4956  }
4957  if(type_size_max_ >= detail::expected_max_vector_size) {
4958  inject_separator_ = true;
4959  }
4960  return this;
4961  }
4962 
4964  void inject_separator(bool value = true) { inject_separator_ = value; }
4965 
4967  Option *default_function(const std::function<std::string()> &func) {
4968  default_function_ = func;
4969  return this;
4970  }
4971 
4974  if(default_function_) {
4975  default_str_ = default_function_();
4976  }
4977  return this;
4978  }
4979 
4981  Option *default_str(std::string val) {
4982  default_str_ = std::move(val);
4983  return this;
4984  }
4985 
4988  template <typename X> Option *default_val(const X &val) {
4989  std::string val_str = detail::to_string(val);
4990  auto old_option_state = current_option_state_;
4991  results_t old_results{std::move(results_)};
4992  results_.clear();
4993  try {
4994  add_result(val_str);
4995  if(run_callback_for_default_) {
4996  run_callback(); // run callback sets the state we need to reset it again
4997  current_option_state_ = option_state::parsing;
4998  } else {
4999  _validate_results(results_);
5000  current_option_state_ = old_option_state;
5001  }
5002  } catch(const CLI::Error &) {
5003  // this should be done
5004  results_ = std::move(old_results);
5005  current_option_state_ = old_option_state;
5006  throw;
5007  }
5008  results_ = std::move(old_results);
5009  default_str_ = std::move(val_str);
5010  return this;
5011  }
5012 
5014  std::string get_type_name() const {
5015  std::string full_type_name = type_name_();
5016  if(!validators_.empty()) {
5017  for(auto &Validator : validators_) {
5018  std::string vtype = Validator.get_description();
5019  if(!vtype.empty()) {
5020  full_type_name += ":" + vtype;
5021  }
5022  }
5023  }
5024  return full_type_name;
5025  }
5026 
5027  private:
5029  void _validate_results(results_t &res) const {
5030  // Run the Validators (can change the string)
5031  if(!validators_.empty()) {
5032  if(type_size_max_ > 1) { // in this context index refers to the index in the type
5033  int index = 0;
5034  if(get_items_expected_max() < static_cast<int>(res.size()) &&
5035  multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
5036  // create a negative index for the earliest ones
5037  index = get_items_expected_max() - static_cast<int>(res.size());
5038  }
5039 
5040  for(std::string &result : res) {
5041  if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) {
5042  index = 0; // reset index for variable size chunks
5043  continue;
5044  }
5045  auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
5046  if(!err_msg.empty())
5047  throw ValidationError(get_name(), err_msg);
5048  ++index;
5049  }
5050  } else {
5051  int index = 0;
5052  if(expected_max_ < static_cast<int>(res.size()) &&
5053  multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
5054  // create a negative index for the earliest ones
5055  index = expected_max_ - static_cast<int>(res.size());
5056  }
5057  for(std::string &result : res) {
5058  auto err_msg = _validate(result, index);
5059  ++index;
5060  if(!err_msg.empty())
5061  throw ValidationError(get_name(), err_msg);
5062  }
5063  }
5064  }
5065  }
5066 
5070  void _reduce_results(results_t &res, const results_t &original) const {
5071 
5072  // max num items expected or length of vector, always at least 1
5073  // Only valid for a trimming policy
5074 
5075  res.clear();
5076  // Operation depends on the policy setting
5077  switch(multi_option_policy_) {
5078  case MultiOptionPolicy::TakeAll:
5079  break;
5080  case MultiOptionPolicy::TakeLast: {
5081  // Allow multi-option sizes (including 0)
5082  std::size_t trim_size = std::min<std::size_t>(
5083  static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
5084  if(original.size() != trim_size) {
5085  res.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
5086  }
5087  } break;
5088  case MultiOptionPolicy::TakeFirst: {
5089  std::size_t trim_size = std::min<std::size_t>(
5090  static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
5091  if(original.size() != trim_size) {
5092  res.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size));
5093  }
5094  } break;
5095  case MultiOptionPolicy::Join:
5096  if(results_.size() > 1) {
5097  res.push_back(detail::join(original, std::string(1, (delimiter_ == '\0') ? '\n' : delimiter_)));
5098  }
5099  break;
5100  case MultiOptionPolicy::Throw:
5101  default: {
5102  auto num_min = static_cast<std::size_t>(get_items_expected_min());
5103  auto num_max = static_cast<std::size_t>(get_items_expected_max());
5104  if(num_min == 0) {
5105  num_min = 1;
5106  }
5107  if(num_max == 0) {
5108  num_max = 1;
5109  }
5110  if(original.size() < num_min) {
5111  throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size());
5112  }
5113  if(original.size() > num_max) {
5114  throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size());
5115  }
5116  break;
5117  }
5118  }
5119  }
5120 
5121  // Run a result through the Validators
5122  std::string _validate(std::string &result, int index) const {
5123  std::string err_msg;
5124  if(result.empty() && expected_min_ == 0) {
5125  // an empty with nothing expected is allowed
5126  return err_msg;
5127  }
5128  for(const auto &vali : validators_) {
5129  auto v = vali.get_application_index();
5130  if(v == -1 || v == index) {
5131  try {
5132  err_msg = vali(result);
5133  } catch(const ValidationError &err) {
5134  err_msg = err.what();
5135  }
5136  if(!err_msg.empty())
5137  break;
5138  }
5139  }
5140 
5141  return err_msg;
5142  }
5143 
5145  int _add_result(std::string &&result, std::vector<std::string> &res) const {
5146  int result_count = 0;
5147  if(allow_extra_args_ && !result.empty() && result.front() == '[' &&
5148  result.back() == ']') { // this is now a vector string likely from the default or user entry
5149  result.pop_back();
5150 
5151  for(auto &var : CLI::detail::split(result.substr(1), ',')) {
5152  if(!var.empty()) {
5153  result_count += _add_result(std::move(var), res);
5154  }
5155  }
5156  return result_count;
5157  }
5158  if(delimiter_ == '\0') {
5159  res.push_back(std::move(result));
5160  ++result_count;
5161  } else {
5162  if((result.find_first_of(delimiter_) != std::string::npos)) {
5163  for(const auto &var : CLI::detail::split(result, delimiter_)) {
5164  if(!var.empty()) {
5165  res.push_back(var);
5166  ++result_count;
5167  }
5168  }
5169  } else {
5170  res.push_back(std::move(result));
5171  ++result_count;
5172  }
5173  }
5174  return result_count;
5175  }
5176 }; // namespace CLI
5177 
5178 
5179 
5180 
5181 #ifndef CLI11_PARSE
5182 #define CLI11_PARSE(app, argc, argv) \
5183  try { \
5184  (app).parse((argc), (argv)); \
5185  } catch(const CLI::ParseError &e) { \
5186  return (app).exit(e); \
5187  }
5188 #endif
5189 
5190 namespace detail {
5191 enum class Classifier { NONE, POSITIONAL_MARK, SHORT, LONG, WINDOWS_STYLE, SUBCOMMAND, SUBCOMMAND_TERMINATOR };
5192 struct AppFriend;
5193 } // namespace detail
5194 
5195 namespace FailureMessage {
5196 std::string simple(const App *app, const Error &e);
5197 std::string help(const App *app, const Error &e);
5198 } // namespace FailureMessage
5199 
5201 
5202 enum class config_extras_mode : char { error = 0, ignore, capture };
5203 
5204 class App;
5205 
5206 using App_p = std::shared_ptr<App>;
5207 
5208 class Option_group;
5210 
5213 class App {
5214  friend Option;
5215  friend detail::AppFriend;
5216 
5217  protected:
5218  // This library follows the Google style guide for member names ending in underscores
5219 
5222 
5224  std::string name_{};
5225 
5227  std::string description_{};
5228 
5230  bool allow_extras_{false};
5231 
5234  config_extras_mode allow_config_extras_{config_extras_mode::ignore};
5235 
5237  bool prefix_command_{false};
5238 
5240  bool has_automatic_name_{false};
5241 
5243  bool required_{false};
5244 
5246  bool disabled_{false};
5247 
5249  bool pre_parse_called_{false};
5250 
5253  bool immediate_callback_{false};
5254 
5256  std::function<void(std::size_t)> pre_parse_callback_{};
5257 
5259  std::function<void()> parse_complete_callback_{};
5260 
5262  std::function<void()> final_callback_{};
5263 
5267 
5269  OptionDefaults option_defaults_{};
5270 
5272  std::vector<Option_p> options_{};
5273 
5277 
5279  std::string footer_{};
5280 
5282  std::function<std::string()> footer_callback_{};
5283 
5285  Option *help_ptr_{nullptr};
5286 
5288  Option *help_all_ptr_{nullptr};
5289 
5291  Option *version_ptr_{nullptr};
5292 
5294  std::shared_ptr<FormatterBase> formatter_{new Formatter()};
5295 
5297  std::function<std::string(const App *, const Error &e)> failure_message_{FailureMessage::simple};
5298 
5302 
5303  using missing_t = std::vector<std::pair<detail::Classifier, std::string>>;
5304 
5308  missing_t missing_{};
5309 
5311  std::vector<Option *> parse_order_{};
5312 
5314  std::vector<App *> parsed_subcommands_{};
5315 
5317  std::set<App *> exclude_subcommands_{};
5318 
5321  std::set<Option *> exclude_options_{};
5322 
5325  std::set<App *> need_subcommands_{};
5326 
5329  std::set<Option *> need_options_{};
5330 
5334 
5336  std::vector<App_p> subcommands_{};
5337 
5339  bool ignore_case_{false};
5340 
5342  bool ignore_underscore_{false};
5343 
5345  bool fallthrough_{false};
5346 
5348  bool allow_windows_style_options_{
5349 #ifdef _WIN32
5350  true
5351 #else
5352  false
5353 #endif
5354  };
5356  bool positionals_at_end_{false};
5357 
5358  enum class startup_mode : char { stable, enabled, disabled };
5361  startup_mode default_startup{startup_mode::stable};
5362 
5364  bool configurable_{false};
5365 
5367  bool validate_positionals_{false};
5368 
5371  bool silent_{false};
5372 
5374  std::uint32_t parsed_{0U};
5375 
5377  std::size_t require_subcommand_min_{0};
5378 
5380  std::size_t require_subcommand_max_{0};
5381 
5383  std::size_t require_option_min_{0};
5384 
5386  std::size_t require_option_max_{0};
5387 
5389  App *parent_{nullptr};
5390 
5392  std::string group_{"Subcommands"};
5393 
5395  std::vector<std::string> aliases_{};
5396 
5400 
5402  Option *config_ptr_{nullptr};
5403 
5405  std::shared_ptr<Config> config_formatter_{new ConfigTOML()};
5406 
5408 
5410  App(std::string app_description, std::string app_name, App *parent)
5411  : name_(std::move(app_name)), description_(std::move(app_description)), parent_(parent) {
5412  // Inherit if not from a nullptr
5413  if(parent_ != nullptr) {
5414  if(parent_->help_ptr_ != nullptr)
5415  set_help_flag(parent_->help_ptr_->get_name(false, true), parent_->help_ptr_->get_description());
5416  if(parent_->help_all_ptr_ != nullptr)
5417  set_help_all_flag(parent_->help_all_ptr_->get_name(false, true),
5418  parent_->help_all_ptr_->get_description());
5419 
5421  option_defaults_ = parent_->option_defaults_;
5422 
5423  // INHERITABLE
5424  failure_message_ = parent_->failure_message_;
5425  allow_extras_ = parent_->allow_extras_;
5426  allow_config_extras_ = parent_->allow_config_extras_;
5427  prefix_command_ = parent_->prefix_command_;
5428  immediate_callback_ = parent_->immediate_callback_;
5429  ignore_case_ = parent_->ignore_case_;
5430  ignore_underscore_ = parent_->ignore_underscore_;
5431  fallthrough_ = parent_->fallthrough_;
5432  validate_positionals_ = parent_->validate_positionals_;
5433  configurable_ = parent_->configurable_;
5434  allow_windows_style_options_ = parent_->allow_windows_style_options_;
5435  group_ = parent_->group_;
5436  footer_ = parent_->footer_;
5437  formatter_ = parent_->formatter_;
5438  config_formatter_ = parent_->config_formatter_;
5439  require_subcommand_max_ = parent_->require_subcommand_max_;
5440  }
5441  }
5442 
5443  public:
5446 
5448  explicit App(std::string app_description = "", std::string app_name = "")
5449  : App(app_description, app_name, nullptr) {
5450  set_help_flag("-h,--help", "Print this help message and exit");
5451  }
5452 
5453  App(const App &) = delete;
5454  App &operator=(const App &) = delete;
5455 
5457  virtual ~App() = default;
5458 
5465  App *callback(std::function<void()> app_callback) {
5466  if(immediate_callback_) {
5467  parse_complete_callback_ = std::move(app_callback);
5468  } else {
5469  final_callback_ = std::move(app_callback);
5470  }
5471  return this;
5472  }
5473 
5476  App *final_callback(std::function<void()> app_callback) {
5477  final_callback_ = std::move(app_callback);
5478  return this;
5479  }
5480 
5483  App *parse_complete_callback(std::function<void()> pc_callback) {
5484  parse_complete_callback_ = std::move(pc_callback);
5485  return this;
5486  }
5487 
5490  App *preparse_callback(std::function<void(std::size_t)> pp_callback) {
5491  pre_parse_callback_ = std::move(pp_callback);
5492  return this;
5493  }
5494 
5496  App *name(std::string app_name = "") {
5497 
5498  if(parent_ != nullptr) {
5499  auto oname = name_;
5500  name_ = app_name;
5501  auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
5502  if(!res.empty()) {
5503  name_ = oname;
5504  throw(OptionAlreadyAdded(app_name + " conflicts with existing subcommand names"));
5505  }
5506  } else {
5507  name_ = app_name;
5508  }
5509  has_automatic_name_ = false;
5510  return this;
5511  }
5512 
5514  App *alias(std::string app_name) {
5515  if(!detail::valid_name_string(app_name)) {
5516  if(app_name.empty()) {
5517  throw IncorrectConstruction("Empty aliases are not allowed");
5518  }
5519  if(!detail::valid_first_char(app_name[0])) {
5520  throw IncorrectConstruction(
5521  "Alias starts with invalid character, allowed characters are [a-zA-z0-9]+'_','?','@' ");
5522  }
5523  for(auto c : app_name) {
5524  if(!detail::valid_later_char(c)) {
5525  throw IncorrectConstruction(std::string("Alias contains invalid character ('") + c +
5526  "'), allowed characters are "
5527  "[a-zA-z0-9]+'_','?','@','.','-' ");
5528  }
5529  }
5530  }
5531 
5532  if(parent_ != nullptr) {
5533  aliases_.push_back(app_name);
5534  auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
5535  if(!res.empty()) {
5536  aliases_.pop_back();
5537  throw(OptionAlreadyAdded("alias already matches an existing subcommand: " + app_name));
5538  }
5539  } else {
5540  aliases_.push_back(app_name);
5541  }
5542 
5543  return this;
5544  }
5545 
5547  App *allow_extras(bool allow = true) {
5548  allow_extras_ = allow;
5549  return this;
5550  }
5551 
5553  App *required(bool require = true) {
5554  required_ = require;
5555  return this;
5556  }
5557 
5559  App *disabled(bool disable = true) {
5560  disabled_ = disable;
5561  return this;
5562  }
5563 
5565  App *silent(bool silence = true) {
5566  silent_ = silence;
5567  return this;
5568  }
5569 
5571  App *disabled_by_default(bool disable = true) {
5572  if(disable) {
5573  default_startup = startup_mode::disabled;
5574  } else {
5575  default_startup = (default_startup == startup_mode::enabled) ? startup_mode::enabled : startup_mode::stable;
5576  }
5577  return this;
5578  }
5579 
5582  App *enabled_by_default(bool enable = true) {
5583  if(enable) {
5584  default_startup = startup_mode::enabled;
5585  } else {
5586  default_startup =
5587  (default_startup == startup_mode::disabled) ? startup_mode::disabled : startup_mode::stable;
5588  }
5589  return this;
5590  }
5591 
5593  App *immediate_callback(bool immediate = true) {
5594  immediate_callback_ = immediate;
5595  if(immediate_callback_) {
5596  if(final_callback_ && !(parse_complete_callback_)) {
5597  std::swap(final_callback_, parse_complete_callback_);
5598  }
5599  } else if(!(final_callback_) && parse_complete_callback_) {
5600  std::swap(final_callback_, parse_complete_callback_);
5601  }
5602  return this;
5603  }
5604 
5606  App *validate_positionals(bool validate = true) {
5607  validate_positionals_ = validate;
5608  return this;
5609  }
5610 
5612  App *allow_config_extras(bool allow = true) {
5613  if(allow) {
5614  allow_config_extras_ = config_extras_mode::capture;
5615  allow_extras_ = true;
5616  } else {
5617  allow_config_extras_ = config_extras_mode::error;
5618  }
5619  return this;
5620  }
5621 
5623  App *allow_config_extras(config_extras_mode mode) {
5624  allow_config_extras_ = mode;
5625  return this;
5626  }
5627 
5629  App *prefix_command(bool allow = true) {
5630  prefix_command_ = allow;
5631  return this;
5632  }
5633 
5635  App *ignore_case(bool value = true) {
5636  if(value && !ignore_case_) {
5637  ignore_case_ = true;
5638  auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
5639  auto &match = _compare_subcommand_names(*this, *p);
5640  if(!match.empty()) {
5641  ignore_case_ = false; // we are throwing so need to be exception invariant
5642  throw OptionAlreadyAdded("ignore case would cause subcommand name conflicts: " + match);
5643  }
5644  }
5645  ignore_case_ = value;
5646  return this;
5647  }
5648 
5651  App *allow_windows_style_options(bool value = true) {
5652  allow_windows_style_options_ = value;
5653  return this;
5654  }
5655 
5657  App *positionals_at_end(bool value = true) {
5658  positionals_at_end_ = value;
5659  return this;
5660  }
5661 
5663  App *configurable(bool value = true) {
5664  configurable_ = value;
5665  return this;
5666  }
5667 
5669  App *ignore_underscore(bool value = true) {
5670  if(value && !ignore_underscore_) {
5671  ignore_underscore_ = true;
5672  auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
5673  auto &match = _compare_subcommand_names(*this, *p);
5674  if(!match.empty()) {
5675  ignore_underscore_ = false;
5676  throw OptionAlreadyAdded("ignore underscore would cause subcommand name conflicts: " + match);
5677  }
5678  }
5679  ignore_underscore_ = value;
5680  return this;
5681  }
5682 
5684  App *formatter(std::shared_ptr<FormatterBase> fmt) {
5685  formatter_ = fmt;
5686  return this;
5687  }
5688 
5690  App *formatter_fn(std::function<std::string(const App *, std::string, AppFormatMode)> fmt) {
5691  formatter_ = std::make_shared<FormatterLambda>(fmt);
5692  return this;
5693  }
5694 
5696  App *config_formatter(std::shared_ptr<Config> fmt) {
5697  config_formatter_ = fmt;
5698  return this;
5699  }
5700 
5702  bool parsed() const { return parsed_ > 0; }
5703 
5705  OptionDefaults *option_defaults() { return &option_defaults_; }
5706 
5710 
5725  Option *add_option(std::string option_name,
5726  callback_t option_callback,
5727  std::string option_description = "",
5728  bool defaulted = false,
5729  std::function<std::string()> func = {}) {
5730  Option myopt{option_name, option_description, option_callback, this};
5731 
5732  if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) {
5733  return *v == myopt;
5734  }) == std::end(options_)) {
5735  options_.emplace_back();
5736  Option_p &option = options_.back();
5737  option.reset(new Option(option_name, option_description, option_callback, this));
5738 
5739  // Set the default string capture function
5740  option->default_function(func);
5741 
5742  // For compatibility with CLI11 1.7 and before, capture the default string here
5743  if(defaulted)
5744  option->capture_default_str();
5745 
5746  // Transfer defaults to the new option
5747  option_defaults_.copy_to(option.get());
5748 
5749  // Don't bother to capture if we already did
5750  if(!defaulted && option->get_always_capture_default())
5751  option->capture_default_str();
5752 
5753  return option.get();
5754  }
5755  // we know something matches now find what it is so we can produce more error information
5756  for(auto &opt : options_) {
5757  auto &matchname = opt->matching_name(myopt);
5758  if(!matchname.empty()) {
5759  throw(OptionAlreadyAdded("added option matched existing option name: " + matchname));
5760  }
5761  }
5762  // this line should not be reached the above loop should trigger the throw
5763  throw(OptionAlreadyAdded("added option matched existing option name")); // LCOV_EXCL_LINE
5764  }
5765 
5767  template <typename AssignTo,
5768  typename ConvertTo = AssignTo,
5769  enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
5770  Option *add_option(std::string option_name,
5771  AssignTo &variable,
5772  std::string option_description = "") {
5773 
5774  auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
5775  return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
5776  };
5777 
5778  Option *opt = add_option(option_name, fun, option_description, false, [&variable]() {
5779  return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
5780  });
5781  opt->type_name(detail::type_name<ConvertTo>());
5782  // these must be actual lvalues since (std::max) sometimes is defined in terms of references and references
5783  // to structs used in the evaluation can be temporary so that would cause issues.
5785  auto XCcount = detail::type_count<ConvertTo>::value;
5786  opt->type_size(detail::type_count_min<ConvertTo>::value, (std::max)(Tcount, XCcount));
5787  opt->expected(detail::expected_count<ConvertTo>::value);
5788  opt->run_callback_for_default();
5789  return opt;
5790  }
5791 
5793  template <typename AssignTo, enable_if_t<!std::is_const<AssignTo>::value, detail::enabler> = detail::dummy>
5794  Option *add_option_no_stream(std::string option_name,
5795  AssignTo &variable,
5796  std::string option_description = "") {
5797 
5798  auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
5799  return detail::lexical_conversion<AssignTo, AssignTo>(res, variable);
5800  };
5801 
5802  Option *opt = add_option(option_name, fun, option_description, false, []() { return std::string{}; });
5803  opt->type_name(detail::type_name<AssignTo>());
5804  opt->type_size(detail::type_count_min<AssignTo>::value, detail::type_count<AssignTo>::value);
5805  opt->expected(detail::expected_count<AssignTo>::value);
5806  opt->run_callback_for_default();
5807  return opt;
5808  }
5809 
5811  template <typename ArgType>
5812  Option *add_option_function(std::string option_name,
5813  const std::function<void(const ArgType &)> &func,
5814  std::string option_description = "") {
5815 
5816  auto fun = [func](const CLI::results_t &res) {
5817  ArgType variable;
5818  bool result = detail::lexical_conversion<ArgType, ArgType>(res, variable);
5819  if(result) {
5820  func(variable);
5821  }
5822  return result;
5823  };
5824 
5825  Option *opt = add_option(option_name, std::move(fun), option_description, false);
5826  opt->type_name(detail::type_name<ArgType>());
5827  opt->type_size(detail::type_count_min<ArgType>::value, detail::type_count<ArgType>::value);
5828  opt->expected(detail::expected_count<ArgType>::value);
5829  return opt;
5830  }
5831 
5833  Option *add_option(std::string option_name) {
5834  return add_option(option_name, CLI::callback_t{}, std::string{}, false);
5835  }
5836 
5838  template <typename T,
5839  enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
5840  detail::dummy>
5841  Option *add_option(std::string option_name, T &option_description) {
5842  return add_option(option_name, CLI::callback_t(), option_description, false);
5843  }
5844 
5846  Option *set_help_flag(std::string flag_name = "", const std::string &help_description = "") {
5847  // take flag_description by const reference otherwise add_flag tries to assign to help_description
5848  if(help_ptr_ != nullptr) {
5849  remove_option(help_ptr_);
5850  help_ptr_ = nullptr;
5851  }
5852 
5853  // Empty name will simply remove the help flag
5854  if(!flag_name.empty()) {
5855  help_ptr_ = add_flag(flag_name, help_description);
5856  help_ptr_->configurable(false);
5857  }
5858 
5859  return help_ptr_;
5860  }
5861 
5863  Option *set_help_all_flag(std::string help_name = "", const std::string &help_description = "") {
5864  // take flag_description by const reference otherwise add_flag tries to assign to flag_description
5865  if(help_all_ptr_ != nullptr) {
5866  remove_option(help_all_ptr_);
5867  help_all_ptr_ = nullptr;
5868  }
5869 
5870  // Empty name will simply remove the help all flag
5871  if(!help_name.empty()) {
5872  help_all_ptr_ = add_flag(help_name, help_description);
5873  help_all_ptr_->configurable(false);
5874  }
5875 
5876  return help_all_ptr_;
5877  }
5878 
5880  Option *set_version_flag(std::string flag_name = "",
5881  const std::string &versionString = "",
5882  const std::string &version_help = "Display program version information and exit") {
5883  // take flag_description by const reference otherwise add_flag tries to assign to version_description
5884  if(version_ptr_ != nullptr) {
5885  remove_option(version_ptr_);
5886  version_ptr_ = nullptr;
5887  }
5888 
5889  // Empty name will simply remove the version flag
5890  if(!flag_name.empty()) {
5891  version_ptr_ = add_flag_callback(
5892  flag_name, [versionString]() { throw(CLI::CallForVersion(versionString, 0)); }, version_help);
5893  version_ptr_->configurable(false);
5894  }
5895 
5896  return version_ptr_;
5897  }
5899  Option *set_version_flag(std::string flag_name,
5900  std::function<std::string()> vfunc,
5901  const std::string &version_help = "Display program version information and exit") {
5902  if(version_ptr_ != nullptr) {
5903  remove_option(version_ptr_);
5904  version_ptr_ = nullptr;
5905  }
5906 
5907  // Empty name will simply remove the version flag
5908  if(!flag_name.empty()) {
5909  version_ptr_ = add_flag_callback(
5910  flag_name, [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); }, version_help);
5911  version_ptr_->configurable(false);
5912  }
5913 
5914  return version_ptr_;
5915  }
5916 
5917  private:
5919  Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
5920  Option *opt;
5921  if(detail::has_default_flag_values(flag_name)) {
5922  // check for default values and if it has them
5923  auto flag_defaults = detail::get_default_flag_values(flag_name);
5924  detail::remove_default_flag_values(flag_name);
5925  opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
5926  for(const auto &fname : flag_defaults)
5927  opt->fnames_.push_back(fname.first);
5928  opt->default_flag_values_ = std::move(flag_defaults);
5929  } else {
5930  opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
5931  }
5932  // flags cannot have positional values
5933  if(opt->get_positional()) {
5934  auto pos_name = opt->get_name(true);
5935  remove_option(opt);
5936  throw IncorrectConstruction::PositionalFlag(pos_name);
5937  }
5938  opt->multi_option_policy(MultiOptionPolicy::TakeLast);
5939  opt->expected(0);
5940  opt->required(false);
5941  return opt;
5942  }
5943 
5944  public:
5946  Option *add_flag(std::string flag_name) { return _add_flag_internal(flag_name, CLI::callback_t(), std::string{}); }
5947 
5951  template <typename T,
5952  enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
5953  detail::dummy>
5954  Option *add_flag(std::string flag_name, T &flag_description) {
5955  return _add_flag_internal(flag_name, CLI::callback_t(), flag_description);
5956  }
5957 
5960  template <typename T,
5961  enable_if_t<std::is_constructible<T, std::int64_t>::value && !is_bool<T>::value, detail::enabler> =
5962  detail::dummy>
5963  Option *add_flag(std::string flag_name,
5964  T &flag_count,
5965  std::string flag_description = "") {
5966  flag_count = 0;
5967  CLI::callback_t fun = [&flag_count](const CLI::results_t &res) {
5968  try {
5969  detail::sum_flag_vector(res, flag_count);
5970  } catch(const std::invalid_argument &) {
5971  return false;
5972  }
5973  return true;
5974  };
5975  return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
5976  ->multi_option_policy(MultiOptionPolicy::TakeAll);
5977  }
5978 
5981  template <typename T,
5982  enable_if_t<!detail::is_mutable_container<T>::value && !std::is_const<T>::value &&
5983  (!std::is_constructible<T, std::int64_t>::value || is_bool<T>::value) &&
5984  !std::is_constructible<std::function<void(int)>, T>::value,
5985  detail::enabler> = detail::dummy>
5986  Option *add_flag(std::string flag_name,
5987  T &flag_result,
5988  std::string flag_description = "") {
5989 
5990  CLI::callback_t fun = [&flag_result](const CLI::results_t &res) {
5991  return CLI::detail::lexical_cast(res[0], flag_result);
5992  };
5993  return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))->run_callback_for_default();
5994  }
5995 
5997  template <typename T,
5998  enable_if_t<!std::is_assignable<std::function<void(std::int64_t)> &, T>::value, detail::enabler> =
5999  detail::dummy>
6000  Option *add_flag(std::string flag_name,
6001  std::vector<T> &flag_results,
6002  std::string flag_description = "") {
6003  CLI::callback_t fun = [&flag_results](const CLI::results_t &res) {
6004  bool retval = true;
6005  for(const auto &elem : res) {
6006  flag_results.emplace_back();
6007  retval &= detail::lexical_cast(elem, flag_results.back());
6008  }
6009  return retval;
6010  };
6011  return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
6012  ->multi_option_policy(MultiOptionPolicy::TakeAll)
6014  }
6015 
6017  Option *add_flag_callback(std::string flag_name,
6018  std::function<void(void)> function,
6019  std::string flag_description = "") {
6020 
6021  CLI::callback_t fun = [function](const CLI::results_t &res) {
6022  bool trigger{false};
6023  auto result = CLI::detail::lexical_cast(res[0], trigger);
6024  if(result && trigger) {
6025  function();
6026  }
6027  return result;
6028  };
6029  return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
6030  }
6031 
6033  Option *add_flag_function(std::string flag_name,
6034  std::function<void(std::int64_t)> function,
6035  std::string flag_description = "") {
6036 
6037  CLI::callback_t fun = [function](const CLI::results_t &res) {
6038  std::int64_t flag_count = 0;
6039  detail::sum_flag_vector(res, flag_count);
6040  function(flag_count);
6041  return true;
6042  };
6043  return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
6044  ->multi_option_policy(MultiOptionPolicy::TakeAll);
6045  }
6046 
6047 #ifdef CLI11_CPP14
6048  Option *add_flag(std::string flag_name,
6050  std::function<void(std::int64_t)> function,
6051  std::string flag_description = "") {
6052  return add_flag_function(std::move(flag_name), std::move(function), std::move(flag_description));
6053  }
6054 #endif
6055 
6057  Option *set_config(std::string option_name = "",
6058  std::string default_filename = "",
6059  const std::string &help_message = "Read an ini file",
6060  bool config_required = false) {
6061 
6062  // Remove existing config if present
6063  if(config_ptr_ != nullptr) {
6064  remove_option(config_ptr_);
6065  config_ptr_ = nullptr; // need to remove the config_ptr completely
6066  }
6067 
6068  // Only add config if option passed
6069  if(!option_name.empty()) {
6070  config_ptr_ = add_option(option_name, help_message);
6071  if(config_required) {
6072  config_ptr_->required();
6073  }
6074  if(!default_filename.empty()) {
6075  config_ptr_->default_str(std::move(default_filename));
6076  }
6077  config_ptr_->configurable(false);
6078  }
6079 
6080  return config_ptr_;
6081  }
6082 
6084  bool remove_option(Option *opt) {
6085  // Make sure no links exist
6086  for(Option_p &op : options_) {
6087  op->remove_needs(opt);
6088  op->remove_excludes(opt);
6089  }
6090 
6091  if(help_ptr_ == opt)
6092  help_ptr_ = nullptr;
6093  if(help_all_ptr_ == opt)
6094  help_all_ptr_ = nullptr;
6095 
6096  auto iterator =
6097  std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
6098  if(iterator != std::end(options_)) {
6099  options_.erase(iterator);
6100  return true;
6101  }
6102  return false;
6103  }
6104 
6106  template <typename T = Option_group>
6107  T *add_option_group(std::string group_name, std::string group_description = "") {
6108  auto option_group = std::make_shared<T>(std::move(group_description), group_name, this);
6109  auto ptr = option_group.get();
6110  // move to App_p for overload resolution on older gcc versions
6111  App_p app_ptr = std::dynamic_pointer_cast<App>(option_group);
6112  add_subcommand(std::move(app_ptr));
6113  return ptr;
6114  }
6115 
6119 
6121  App *add_subcommand(std::string subcommand_name = "", std::string subcommand_description = "") {
6122  if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
6123  if(!detail::valid_first_char(subcommand_name[0])) {
6124  throw IncorrectConstruction(
6125  "Subcommand name starts with invalid character, allowed characters are [a-zA-z0-9]+'_','?','@' ");
6126  }
6127  for(auto c : subcommand_name) {
6128  if(!detail::valid_later_char(c)) {
6129  throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
6130  "'), allowed characters are "
6131  "[a-zA-z0-9]+'_','?','@','.','-' ");
6132  }
6133  }
6134  }
6135  CLI::App_p subcom = std::shared_ptr<App>(new App(std::move(subcommand_description), subcommand_name, this));
6136  return add_subcommand(std::move(subcom));
6137  }
6138 
6140  App *add_subcommand(CLI::App_p subcom) {
6141  if(!subcom)
6142  throw IncorrectConstruction("passed App is not valid");
6143  auto ckapp = (name_.empty() && parent_ != nullptr) ? _get_fallthrough_parent() : this;
6144  auto &mstrg = _compare_subcommand_names(*subcom, *ckapp);
6145  if(!mstrg.empty()) {
6146  throw(OptionAlreadyAdded("subcommand name or alias matches existing subcommand: " + mstrg));
6147  }
6148  subcom->parent_ = this;
6149  subcommands_.push_back(std::move(subcom));
6150  return subcommands_.back().get();
6151  }
6152 
6154  bool remove_subcommand(App *subcom) {
6155  // Make sure no links exist
6156  for(App_p &sub : subcommands_) {
6157  sub->remove_excludes(subcom);
6158  sub->remove_needs(subcom);
6159  }
6160 
6161  auto iterator = std::find_if(
6162  std::begin(subcommands_), std::end(subcommands_), [subcom](const App_p &v) { return v.get() == subcom; });
6163  if(iterator != std::end(subcommands_)) {
6164  subcommands_.erase(iterator);
6165  return true;
6166  }
6167  return false;
6168  }
6171  App *get_subcommand(const App *subcom) const {
6172  if(subcom == nullptr)
6173  throw OptionNotFound("nullptr passed");
6174  for(const App_p &subcomptr : subcommands_)
6175  if(subcomptr.get() == subcom)
6176  return subcomptr.get();
6177  throw OptionNotFound(subcom->get_name());
6178  }
6179 
6181  App *get_subcommand(std::string subcom) const {
6182  auto subc = _find_subcommand(subcom, false, false);
6183  if(subc == nullptr)
6184  throw OptionNotFound(subcom);
6185  return subc;
6186  }
6188  App *get_subcommand(int index = 0) const {
6189  if(index >= 0) {
6190  auto uindex = static_cast<unsigned>(index);
6191  if(uindex < subcommands_.size())
6192  return subcommands_[uindex].get();
6193  }
6194  throw OptionNotFound(std::to_string(index));
6195  }
6196 
6198  CLI::App_p get_subcommand_ptr(App *subcom) const {
6199  if(subcom == nullptr)
6200  throw OptionNotFound("nullptr passed");
6201  for(const App_p &subcomptr : subcommands_)
6202  if(subcomptr.get() == subcom)
6203  return subcomptr;
6204  throw OptionNotFound(subcom->get_name());
6205  }
6206 
6208  CLI::App_p get_subcommand_ptr(std::string subcom) const {
6209  for(const App_p &subcomptr : subcommands_)
6210  if(subcomptr->check_name(subcom))
6211  return subcomptr;
6212  throw OptionNotFound(subcom);
6213  }
6214 
6216  CLI::App_p get_subcommand_ptr(int index = 0) const {
6217  if(index >= 0) {
6218  auto uindex = static_cast<unsigned>(index);
6219  if(uindex < subcommands_.size())
6220  return subcommands_[uindex];
6221  }
6222  throw OptionNotFound(std::to_string(index));
6223  }
6224 
6226  App *get_option_group(std::string group_name) const {
6227  for(const App_p &app : subcommands_) {
6228  if(app->name_.empty() && app->group_ == group_name) {
6229  return app.get();
6230  }
6231  }
6232  throw OptionNotFound(group_name);
6233  }
6234 
6238  std::size_t count() const { return parsed_; }
6239 
6242  std::size_t count_all() const {
6243  std::size_t cnt{0};
6244  for(auto &opt : options_) {
6245  cnt += opt->count();
6246  }
6247  for(auto &sub : subcommands_) {
6248  cnt += sub->count_all();
6249  }
6250  if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called
6251  cnt += parsed_;
6252  }
6253  return cnt;
6254  }
6255 
6257  App *group(std::string group_name) {
6258  group_ = group_name;
6259  return this;
6260  }
6261 
6264  require_subcommand_min_ = 1;
6265  require_subcommand_max_ = 0;
6266  return this;
6267  }
6268 
6272  App *require_subcommand(int value) {
6273  if(value < 0) {
6274  require_subcommand_min_ = 0;
6275  require_subcommand_max_ = static_cast<std::size_t>(-value);
6276  } else {
6277  require_subcommand_min_ = static_cast<std::size_t>(value);
6278  require_subcommand_max_ = static_cast<std::size_t>(value);
6279  }
6280  return this;
6281  }
6282 
6285  App *require_subcommand(std::size_t min, std::size_t max) {
6286  require_subcommand_min_ = min;
6287  require_subcommand_max_ = max;
6288  return this;
6289  }
6290 
6293  require_option_min_ = 1;
6294  require_option_max_ = 0;
6295  return this;
6296  }
6297 
6301  App *require_option(int value) {
6302  if(value < 0) {
6303  require_option_min_ = 0;
6304  require_option_max_ = static_cast<std::size_t>(-value);
6305  } else {
6306  require_option_min_ = static_cast<std::size_t>(value);
6307  require_option_max_ = static_cast<std::size_t>(value);
6308  }
6309  return this;
6310  }
6311 
6314  App *require_option(std::size_t min, std::size_t max) {
6315  require_option_min_ = min;
6316  require_option_max_ = max;
6317  return this;
6318  }
6319 
6322  App *fallthrough(bool value = true) {
6323  fallthrough_ = value;
6324  return this;
6325  }
6326 
6329  explicit operator bool() const { return parsed_ > 0; }
6330 
6334 
6338  virtual void pre_callback() {}
6339 
6343  //
6345  void clear() {
6346 
6347  parsed_ = 0;
6348  pre_parse_called_ = false;
6349 
6350  missing_.clear();
6351  parsed_subcommands_.clear();
6352  for(const Option_p &opt : options_) {
6353  opt->clear();
6354  }
6355  for(const App_p &subc : subcommands_) {
6356  subc->clear();
6357  }
6358  }
6359 
6362  void parse(int argc, const char *const *argv) {
6363  // If the name is not set, read from command line
6364  if(name_.empty() || has_automatic_name_) {
6365  has_automatic_name_ = true;
6366  name_ = argv[0];
6367  }
6368 
6369  std::vector<std::string> args;
6370  args.reserve(static_cast<std::size_t>(argc) - 1);
6371  for(int i = argc - 1; i > 0; i--)
6372  args.emplace_back(argv[i]);
6373  parse(std::move(args));
6374  }
6375 
6380  void parse(std::string commandline, bool program_name_included = false) {
6381 
6382  if(program_name_included) {
6383  auto nstr = detail::split_program_name(commandline);
6384  if((name_.empty()) || (has_automatic_name_)) {
6385  has_automatic_name_ = true;
6386  name_ = nstr.first;
6387  }
6388  commandline = std::move(nstr.second);
6389  } else {
6390  detail::trim(commandline);
6391  }
6392  // the next section of code is to deal with quoted arguments after an '=' or ':' for windows like operations
6393  if(!commandline.empty()) {
6394  commandline = detail::find_and_modify(commandline, "=", detail::escape_detect);
6395  if(allow_windows_style_options_)
6396  commandline = detail::find_and_modify(commandline, ":", detail::escape_detect);
6397  }
6398 
6399  auto args = detail::split_up(std::move(commandline));
6400  // remove all empty strings
6401  args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
6402  std::reverse(args.begin(), args.end());
6403 
6404  parse(std::move(args));
6405  }
6406 
6409  void parse(std::vector<std::string> &args) {
6410  // Clear if parsed
6411  if(parsed_ > 0)
6412  clear();
6413 
6414  // parsed_ is incremented in commands/subcommands,
6415  // but placed here to make sure this is cleared when
6416  // running parse after an error is thrown, even by _validate or _configure.
6417  parsed_ = 1;
6418  _validate();
6419  _configure();
6420  // set the parent as nullptr as this object should be the top now
6421  parent_ = nullptr;
6422  parsed_ = 0;
6423 
6424  _parse(args);
6425  run_callback();
6426  }
6427 
6429  void parse(std::vector<std::string> &&args) {
6430  // Clear if parsed
6431  if(parsed_ > 0)
6432  clear();
6433 
6434  // parsed_ is incremented in commands/subcommands,
6435  // but placed here to make sure this is cleared when
6436  // running parse after an error is thrown, even by _validate or _configure.
6437  parsed_ = 1;
6438  _validate();
6439  _configure();
6440  // set the parent as nullptr as this object should be the top now
6441  parent_ = nullptr;
6442  parsed_ = 0;
6443 
6444  _parse(std::move(args));
6445  run_callback();
6446  }
6447 
6449  void failure_message(std::function<std::string(const App *, const Error &e)> function) {
6450  failure_message_ = function;
6451  }
6452 
6454  int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {
6455 
6457  if(e.get_name() == "RuntimeError")
6458  return e.get_exit_code();
6459 
6460  if(e.get_name() == "CallForHelp") {
6461  out << help();
6462  return e.get_exit_code();
6463  }
6464 
6465  if(e.get_name() == "CallForAllHelp") {
6466  out << help("", AppFormatMode::All);
6467  return e.get_exit_code();
6468  }
6469 
6470  if(e.get_name() == "CallForVersion") {
6471  out << e.what() << std::endl;
6472  return e.get_exit_code();
6473  }
6474 
6475  if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
6476  if(failure_message_)
6477  err << failure_message_(this, e) << std::flush;
6478  }
6479 
6480  return e.get_exit_code();
6481  }
6482 
6486 
6488  std::size_t count(std::string option_name) const { return get_option(option_name)->count(); }
6489 
6492  std::vector<App *> get_subcommands() const { return parsed_subcommands_; }
6493 
6496  std::vector<const App *> get_subcommands(const std::function<bool(const App *)> &filter) const {
6497  std::vector<const App *> subcomms(subcommands_.size());
6498  std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
6499  return v.get();
6500  });
6501 
6502  if(filter) {
6503  subcomms.erase(std::remove_if(std::begin(subcomms),
6504  std::end(subcomms),
6505  [&filter](const App *app) { return !filter(app); }),
6506  std::end(subcomms));
6507  }
6508 
6509  return subcomms;
6510  }
6511 
6514  std::vector<App *> get_subcommands(const std::function<bool(App *)> &filter) {
6515  std::vector<App *> subcomms(subcommands_.size());
6516  std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
6517  return v.get();
6518  });
6519 
6520  if(filter) {
6521  subcomms.erase(
6522  std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](App *app) { return !filter(app); }),
6523  std::end(subcomms));
6524  }
6525 
6526  return subcomms;
6527  }
6528 
6530  bool got_subcommand(const App *subcom) const {
6531  // get subcom needed to verify that this was a real subcommand
6532  return get_subcommand(subcom)->parsed_ > 0;
6533  }
6534 
6536  bool got_subcommand(std::string subcommand_name) const { return get_subcommand(subcommand_name)->parsed_ > 0; }
6537 
6540  if(opt == nullptr) {
6541  throw OptionNotFound("nullptr passed");
6542  }
6543  exclude_options_.insert(opt);
6544  return this;
6545  }
6546 
6548  App *excludes(App *app) {
6549  if(app == nullptr) {
6550  throw OptionNotFound("nullptr passed");
6551  }
6552  if(app == this) {
6553  throw OptionNotFound("cannot self reference in needs");
6554  }
6555  auto res = exclude_subcommands_.insert(app);
6556  // subcommand exclusion should be symmetric
6557  if(res.second) {
6558  app->exclude_subcommands_.insert(this);
6559  }
6560  return this;
6561  }
6562 
6563  App *needs(Option *opt) {
6564  if(opt == nullptr) {
6565  throw OptionNotFound("nullptr passed");
6566  }
6567  need_options_.insert(opt);
6568  return this;
6569  }
6570 
6571  App *needs(App *app) {
6572  if(app == nullptr) {
6573  throw OptionNotFound("nullptr passed");
6574  }
6575  if(app == this) {
6576  throw OptionNotFound("cannot self reference in needs");
6577  }
6578  need_subcommands_.insert(app);
6579  return this;
6580  }
6581 
6584  auto iterator = std::find(std::begin(exclude_options_), std::end(exclude_options_), opt);
6585  if(iterator == std::end(exclude_options_)) {
6586  return false;
6587  }
6588  exclude_options_.erase(iterator);
6589  return true;
6590  }
6591 
6593  bool remove_excludes(App *app) {
6594  auto iterator = std::find(std::begin(exclude_subcommands_), std::end(exclude_subcommands_), app);
6595  if(iterator == std::end(exclude_subcommands_)) {
6596  return false;
6597  }
6598  auto other_app = *iterator;
6599  exclude_subcommands_.erase(iterator);
6600  other_app->remove_excludes(this);
6601  return true;
6602  }
6603 
6605  bool remove_needs(Option *opt) {
6606  auto iterator = std::find(std::begin(need_options_), std::end(need_options_), opt);
6607  if(iterator == std::end(need_options_)) {
6608  return false;
6609  }
6610  need_options_.erase(iterator);
6611  return true;
6612  }
6613 
6615  bool remove_needs(App *app) {
6616  auto iterator = std::find(std::begin(need_subcommands_), std::end(need_subcommands_), app);
6617  if(iterator == std::end(need_subcommands_)) {
6618  return false;
6619  }
6620  need_subcommands_.erase(iterator);
6621  return true;
6622  }
6623 
6627 
6629  App *footer(std::string footer_string) {
6630  footer_ = std::move(footer_string);
6631  return this;
6632  }
6634  App *footer(std::function<std::string()> footer_function) {
6635  footer_callback_ = std::move(footer_function);
6636  return this;
6637  }
6640  std::string config_to_str(bool default_also = false, bool write_description = false) const {
6641  return config_formatter_->to_config(this, default_also, write_description, "");
6642  }
6643 
6646  std::string help(std::string prev = "", AppFormatMode mode = AppFormatMode::Normal) const {
6647  if(prev.empty())
6648  prev = get_name();
6649  else
6650  prev += " " + get_name();
6651 
6652  // Delegate to subcommand if needed
6653  auto selected_subcommands = get_subcommands();
6654  if(!selected_subcommands.empty()) {
6655  return selected_subcommands.at(0)->help(prev, mode);
6656  }
6657  return formatter_->make_help(this, prev, mode);
6658  }
6659 
6661  std::string version() const {
6662  std::string val;
6663  if(version_ptr_ != nullptr) {
6664  auto rv = version_ptr_->results();
6665  version_ptr_->clear();
6666  version_ptr_->add_result("true");
6667  try {
6668  version_ptr_->run_callback();
6669  } catch(const CLI::CallForVersion &cfv) {
6670  val = cfv.what();
6671  }
6672  version_ptr_->clear();
6673  version_ptr_->add_result(rv);
6674  }
6675  return val;
6676  }
6680 
6682  std::shared_ptr<FormatterBase> get_formatter() const { return formatter_; }
6683 
6685  std::shared_ptr<Config> get_config_formatter() const { return config_formatter_; }
6686 
6688  std::shared_ptr<ConfigBase> get_config_formatter_base() const {
6689  // This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase
6690 #if defined(__cpp_rtti) || (defined(__GXX_RTTI) && __GXX_RTTI) || (defined(_HAS_STATIC_RTTI) && (_HAS_STATIC_RTTI == 0))
6691  return std::dynamic_pointer_cast<ConfigBase>(config_formatter_);
6692 #else
6693  return std::static_pointer_cast<ConfigBase>(config_formatter_);
6694 #endif
6695  }
6696 
6698  std::string get_description() const { return description_; }
6699 
6701  App *description(std::string app_description) {
6702  description_ = std::move(app_description);
6703  return this;
6704  }
6705 
6707  std::vector<const Option *> get_options(const std::function<bool(const Option *)> filter = {}) const {
6708  std::vector<const Option *> options(options_.size());
6709  std::transform(std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) {
6710  return val.get();
6711  });
6712 
6713  if(filter) {
6714  options.erase(std::remove_if(std::begin(options),
6715  std::end(options),
6716  [&filter](const Option *opt) { return !filter(opt); }),
6717  std::end(options));
6718  }
6719 
6720  return options;
6721  }
6722 
6724  std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {}) {
6725  std::vector<Option *> options(options_.size());
6726  std::transform(std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) {
6727  return val.get();
6728  });
6729 
6730  if(filter) {
6731  options.erase(
6732  std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) { return !filter(opt); }),
6733  std::end(options));
6734  }
6735 
6736  return options;
6737  }
6738 
6740  Option *get_option_no_throw(std::string option_name) noexcept {
6741  for(Option_p &opt : options_) {
6742  if(opt->check_name(option_name)) {
6743  return opt.get();
6744  }
6745  }
6746  for(auto &subc : subcommands_) {
6747  // also check down into nameless subcommands
6748  if(subc->get_name().empty()) {
6749  auto opt = subc->get_option_no_throw(option_name);
6750  if(opt != nullptr) {
6751  return opt;
6752  }
6753  }
6754  }
6755  return nullptr;
6756  }
6757 
6759  const Option *get_option_no_throw(std::string option_name) const noexcept {
6760  for(const Option_p &opt : options_) {
6761  if(opt->check_name(option_name)) {
6762  return opt.get();
6763  }
6764  }
6765  for(const auto &subc : subcommands_) {
6766  // also check down into nameless subcommands
6767  if(subc->get_name().empty()) {
6768  auto opt = subc->get_option_no_throw(option_name);
6769  if(opt != nullptr) {
6770  return opt;
6771  }
6772  }
6773  }
6774  return nullptr;
6775  }
6776 
6778  const Option *get_option(std::string option_name) const {
6779  auto opt = get_option_no_throw(option_name);
6780  if(opt == nullptr) {
6781  throw OptionNotFound(option_name);
6782  }
6783  return opt;
6784  }
6785 
6787  Option *get_option(std::string option_name) {
6788  auto opt = get_option_no_throw(option_name);
6789  if(opt == nullptr) {
6790  throw OptionNotFound(option_name);
6791  }
6792  return opt;
6793  }
6794 
6796  const Option *operator[](const std::string &option_name) const { return get_option(option_name); }
6797 
6799  const Option *operator[](const char *option_name) const { return get_option(option_name); }
6800 
6802  bool get_ignore_case() const { return ignore_case_; }
6803 
6805  bool get_ignore_underscore() const { return ignore_underscore_; }
6806 
6808  bool get_fallthrough() const { return fallthrough_; }
6809 
6811  bool get_allow_windows_style_options() const { return allow_windows_style_options_; }
6812 
6814  bool get_positionals_at_end() const { return positionals_at_end_; }
6815 
6817  bool get_configurable() const { return configurable_; }
6818 
6820  const std::string &get_group() const { return group_; }
6821 
6823  std::string get_footer() const { return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_; }
6824 
6826  std::size_t get_require_subcommand_min() const { return require_subcommand_min_; }
6827 
6829  std::size_t get_require_subcommand_max() const { return require_subcommand_max_; }
6830 
6832  std::size_t get_require_option_min() const { return require_option_min_; }
6833 
6835  std::size_t get_require_option_max() const { return require_option_max_; }
6836 
6838  bool get_prefix_command() const { return prefix_command_; }
6839 
6841  bool get_allow_extras() const { return allow_extras_; }
6842 
6844  bool get_required() const { return required_; }
6845 
6847  bool get_disabled() const { return disabled_; }
6848 
6850  bool get_silent() const { return silent_; }
6851 
6853  bool get_immediate_callback() const { return immediate_callback_; }
6854 
6856  bool get_disabled_by_default() const { return (default_startup == startup_mode::disabled); }
6857 
6859  bool get_enabled_by_default() const { return (default_startup == startup_mode::enabled); }
6861  bool get_validate_positionals() const { return validate_positionals_; }
6862 
6864  config_extras_mode get_allow_config_extras() const { return allow_config_extras_; }
6865 
6867  Option *get_help_ptr() { return help_ptr_; }
6868 
6870  const Option *get_help_ptr() const { return help_ptr_; }
6871 
6873  const Option *get_help_all_ptr() const { return help_all_ptr_; }
6874 
6876  Option *get_config_ptr() { return config_ptr_; }
6877 
6879  const Option *get_config_ptr() const { return config_ptr_; }
6880 
6882  Option *get_version_ptr() { return version_ptr_; }
6883 
6885  const Option *get_version_ptr() const { return version_ptr_; }
6886 
6888  App *get_parent() { return parent_; }
6889 
6891  const App *get_parent() const { return parent_; }
6892 
6894  const std::string &get_name() const { return name_; }
6895 
6897  const std::vector<std::string> &get_aliases() const { return aliases_; }
6898 
6901  aliases_.clear();
6902  return this;
6903  }
6904 
6906  std::string get_display_name(bool with_aliases = false) const {
6907  if(name_.empty()) {
6908  return std::string("[Option Group: ") + get_group() + "]";
6909  }
6910  if(aliases_.empty() || !with_aliases || aliases_.empty()) {
6911  return name_;
6912  }
6913  std::string dispname = name_;
6914  for(const auto &lalias : aliases_) {
6915  dispname.push_back(',');
6916  dispname.push_back(' ');
6917  dispname.append(lalias);
6918  }
6919  return dispname;
6920  }
6921 
6923  bool check_name(std::string name_to_check) const {
6924  std::string local_name = name_;
6925  if(ignore_underscore_) {
6926  local_name = detail::remove_underscore(name_);
6927  name_to_check = detail::remove_underscore(name_to_check);
6928  }
6929  if(ignore_case_) {
6930  local_name = detail::to_lower(name_);
6931  name_to_check = detail::to_lower(name_to_check);
6932  }
6933 
6934  if(local_name == name_to_check) {
6935  return true;
6936  }
6937  for(auto les : aliases_) {
6938  if(ignore_underscore_) {
6939  les = detail::remove_underscore(les);
6940  }
6941  if(ignore_case_) {
6942  les = detail::to_lower(les);
6943  }
6944  if(les == name_to_check) {
6945  return true;
6946  }
6947  }
6948  return false;
6949  }
6950 
6952  std::vector<std::string> get_groups() const {
6953  std::vector<std::string> groups;
6954 
6955  for(const Option_p &opt : options_) {
6956  // Add group if it is not already in there
6957  if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {
6958  groups.push_back(opt->get_group());
6959  }
6960  }
6961 
6962  return groups;
6963  }
6964 
6966  const std::vector<Option *> &parse_order() const { return parse_order_; }
6967 
6969  std::vector<std::string> remaining(bool recurse = false) const {
6970  std::vector<std::string> miss_list;
6971  for(const std::pair<detail::Classifier, std::string> &miss : missing_) {
6972  miss_list.push_back(std::get<1>(miss));
6973  }
6974  // Get from a subcommand that may allow extras
6975  if(recurse) {
6976  if(!allow_extras_) {
6977  for(const auto &sub : subcommands_) {
6978  if(sub->name_.empty() && !sub->missing_.empty()) {
6979  for(const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {
6980  miss_list.push_back(std::get<1>(miss));
6981  }
6982  }
6983  }
6984  }
6985  // Recurse into subcommands
6986 
6987  for(const App *sub : parsed_subcommands_) {
6988  std::vector<std::string> output = sub->remaining(recurse);
6989  std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
6990  }
6991  }
6992  return miss_list;
6993  }
6994 
6996  std::vector<std::string> remaining_for_passthrough(bool recurse = false) const {
6997  std::vector<std::string> miss_list = remaining(recurse);
6998  std::reverse(std::begin(miss_list), std::end(miss_list));
6999  return miss_list;
7000  }
7001 
7003  std::size_t remaining_size(bool recurse = false) const {
7004  auto remaining_options = static_cast<std::size_t>(std::count_if(
7005  std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifier, std::string> &val) {
7006  return val.first != detail::Classifier::POSITIONAL_MARK;
7007  }));
7008 
7009  if(recurse) {
7010  for(const App_p &sub : subcommands_) {
7011  remaining_options += sub->remaining_size(recurse);
7012  }
7013  }
7014  return remaining_options;
7015  }
7016 
7018 
7019  protected:
7024  void _validate() const {
7025  // count the number of positional only args
7026  auto pcount = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
7027  return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();
7028  });
7029  if(pcount > 1) {
7030  auto pcount_req = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
7031  return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&
7032  opt->get_required();
7033  });
7034  if(pcount - pcount_req > 1) {
7035  throw InvalidError(name_);
7036  }
7037  }
7038 
7039  std::size_t nameless_subs{0};
7040  for(const App_p &app : subcommands_) {
7041  app->_validate();
7042  if(app->get_name().empty())
7043  ++nameless_subs;
7044  }
7045 
7046  if(require_option_min_ > 0) {
7047  if(require_option_max_ > 0) {
7048  if(require_option_max_ < require_option_min_) {
7049  throw(InvalidError("Required min options greater than required max options",
7050  ExitCodes::InvalidError));
7051  }
7052  }
7053  if(require_option_min_ > (options_.size() + nameless_subs)) {
7054  throw(InvalidError("Required min options greater than number of available options",
7055  ExitCodes::InvalidError));
7056  }
7057  }
7058  }
7059 
7063  void _configure() {
7064  if(default_startup == startup_mode::enabled) {
7065  disabled_ = false;
7066  } else if(default_startup == startup_mode::disabled) {
7067  disabled_ = true;
7068  }
7069  for(const App_p &app : subcommands_) {
7070  if(app->has_automatic_name_) {
7071  app->name_.clear();
7072  }
7073  if(app->name_.empty()) {
7074  app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop
7075  app->prefix_command_ = false;
7076  }
7077  // make sure the parent is set to be this object in preparation for parse
7078  app->parent_ = this;
7079  app->_configure();
7080  }
7081  }
7082 
7084  void run_callback(bool final_mode = false, bool suppress_final_callback = false) {
7085  pre_callback();
7086  // in the main app if immediate_callback_ is set it runs the main callback before the used subcommands
7087  if(!final_mode && parse_complete_callback_) {
7088  parse_complete_callback_();
7089  }
7090  // run the callbacks for the received subcommands
7091  for(App *subc : get_subcommands()) {
7092  subc->run_callback(true, suppress_final_callback);
7093  }
7094  // now run callbacks for option_groups
7095  for(auto &subc : subcommands_) {
7096  if(subc->name_.empty() && subc->count_all() > 0) {
7097  subc->run_callback(true, suppress_final_callback);
7098  }
7099  }
7100 
7101  // finally run the main callback
7102  if(final_callback_ && (parsed_ > 0) && (!suppress_final_callback)) {
7103  if(!name_.empty() || count_all() > 0 || parent_ == nullptr) {
7104  final_callback_();
7105  }
7106  }
7107  }
7108 
7110  bool _valid_subcommand(const std::string &current, bool ignore_used = true) const {
7111  // Don't match if max has been reached - but still check parents
7112  if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
7113  return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
7114  }
7115  auto com = _find_subcommand(current, true, ignore_used);
7116  if(com != nullptr) {
7117  return true;
7118  }
7119  // Check parent if exists, else return false
7120  return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
7121  }
7122 
7124  detail::Classifier _recognize(const std::string &current, bool ignore_used_subcommands = true) const {
7125  std::string dummy1, dummy2;
7126 
7127  if(current == "--")
7128  return detail::Classifier::POSITIONAL_MARK;
7129  if(_valid_subcommand(current, ignore_used_subcommands))
7130  return detail::Classifier::SUBCOMMAND;
7131  if(detail::split_long(current, dummy1, dummy2))
7132  return detail::Classifier::LONG;
7133  if(detail::split_short(current, dummy1, dummy2)) {
7134  if(dummy1[0] >= '0' && dummy1[0] <= '9') {
7135  if(get_option_no_throw(std::string{'-', dummy1[0]}) == nullptr) {
7136  return detail::Classifier::NONE;
7137  }
7138  }
7139  return detail::Classifier::SHORT;
7140  }
7141  if((allow_windows_style_options_) && (detail::split_windows_style(current, dummy1, dummy2)))
7142  return detail::Classifier::WINDOWS_STYLE;
7143  if((current == "++") && !name_.empty() && parent_ != nullptr)
7144  return detail::Classifier::SUBCOMMAND_TERMINATOR;
7145  return detail::Classifier::NONE;
7146  }
7147 
7148  // The parse function is now broken into several parts, and part of process
7149 
7152  if(config_ptr_ != nullptr) {
7153  bool config_required = config_ptr_->get_required();
7154  auto file_given = config_ptr_->count() > 0;
7155  auto config_files = config_ptr_->as<std::vector<std::string>>();
7156  if(config_files.empty() || config_files.front().empty()) {
7157  if(config_required) {
7158  throw FileError::Missing("no specified config file");
7159  }
7160  return;
7161  }
7162  for(auto rit = config_files.rbegin(); rit != config_files.rend(); ++rit) {
7163  const auto &config_file = *rit;
7164  auto path_result = detail::check_path(config_file.c_str());
7165  if(path_result == detail::path_type::file) {
7166  try {
7167  std::vector<ConfigItem> values = config_formatter_->from_file(config_file);
7168  _parse_config(values);
7169  if(!file_given) {
7170  config_ptr_->add_result(config_file);
7171  }
7172  } catch(const FileError &) {
7173  if(config_required || file_given)
7174  throw;
7175  }
7176  } else if(config_required || file_given) {
7177  throw FileError::Missing(config_file);
7178  }
7179  }
7180  }
7181  }
7182 
7184  void _process_env() {
7185  for(const Option_p &opt : options_) {
7186  if(opt->count() == 0 && !opt->envname_.empty()) {
7187  char *buffer = nullptr;
7188  std::string ename_string;
7189 
7190 #ifdef _MSC_VER
7191  // Windows version
7192  std::size_t sz = 0;
7193  if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {
7194  ename_string = std::string(buffer);
7195  free(buffer);
7196  }
7197 #else
7198  // This also works on Windows, but gives a warning
7199  buffer = std::getenv(opt->envname_.c_str());
7200  if(buffer != nullptr)
7201  ename_string = std::string(buffer);
7202 #endif
7203 
7204  if(!ename_string.empty()) {
7205  opt->add_result(ename_string);
7206  }
7207  }
7208  }
7209 
7210  for(App_p &sub : subcommands_) {
7211  if(sub->get_name().empty() || !sub->parse_complete_callback_)
7212  sub->_process_env();
7213  }
7214  }
7215 
7218 
7219  for(App_p &sub : subcommands_) {
7220  // process the priority option_groups first
7221  if(sub->get_name().empty() && sub->parse_complete_callback_) {
7222  if(sub->count_all() > 0) {
7223  sub->_process_callbacks();
7224  sub->run_callback();
7225  }
7226  }
7227  }
7228 
7229  for(const Option_p &opt : options_) {
7230  if(opt->count() > 0 && !opt->get_callback_run()) {
7231  opt->run_callback();
7232  }
7233  }
7234  for(App_p &sub : subcommands_) {
7235  if(!sub->parse_complete_callback_) {
7236  sub->_process_callbacks();
7237  }
7238  }
7239  }
7240 
7244  void _process_help_flags(bool trigger_help = false, bool trigger_all_help = false) const {
7245  const Option *help_ptr = get_help_ptr();
7246  const Option *help_all_ptr = get_help_all_ptr();
7247 
7248  if(help_ptr != nullptr && help_ptr->count() > 0)
7249  trigger_help = true;
7250  if(help_all_ptr != nullptr && help_all_ptr->count() > 0)
7251  trigger_all_help = true;
7252 
7253  // If there were parsed subcommands, call those. First subcommand wins if there are multiple ones.
7254  if(!parsed_subcommands_.empty()) {
7255  for(const App *sub : parsed_subcommands_)
7256  sub->_process_help_flags(trigger_help, trigger_all_help);
7257 
7258  // Only the final subcommand should call for help. All help wins over help.
7259  } else if(trigger_all_help) {
7260  throw CallForAllHelp();
7261  } else if(trigger_help) {
7262  throw CallForHelp();
7263  }
7264  }
7265 
7268  // check excludes
7269  bool excluded{false};
7270  std::string excluder;
7271  for(auto &opt : exclude_options_) {
7272  if(opt->count() > 0) {
7273  excluded = true;
7274  excluder = opt->get_name();
7275  }
7276  }
7277  for(auto &subc : exclude_subcommands_) {
7278  if(subc->count_all() > 0) {
7279  excluded = true;
7280  excluder = subc->get_display_name();
7281  }
7282  }
7283  if(excluded) {
7284  if(count_all() > 0) {
7285  throw ExcludesError(get_display_name(), excluder);
7286  }
7287  // if we are excluded but didn't receive anything, just return
7288  return;
7289  }
7290 
7291  // check excludes
7292  bool missing_needed{false};
7293  std::string missing_need;
7294  for(auto &opt : need_options_) {
7295  if(opt->count() == 0) {
7296  missing_needed = true;
7297  missing_need = opt->get_name();
7298  }
7299  }
7300  for(auto &subc : need_subcommands_) {
7301  if(subc->count_all() == 0) {
7302  missing_needed = true;
7303  missing_need = subc->get_display_name();
7304  }
7305  }
7306  if(missing_needed) {
7307  if(count_all() > 0) {
7308  throw RequiresError(get_display_name(), missing_need);
7309  }
7310  // if we missing something but didn't have any options, just return
7311  return;
7312  }
7313 
7314  std::size_t used_options = 0;
7315  for(const Option_p &opt : options_) {
7316 
7317  if(opt->count() != 0) {
7318  ++used_options;
7319  }
7320  // Required but empty
7321  if(opt->get_required() && opt->count() == 0) {
7322  throw RequiredError(opt->get_name());
7323  }
7324  // Requires
7325  for(const Option *opt_req : opt->needs_)
7326  if(opt->count() > 0 && opt_req->count() == 0)
7327  throw RequiresError(opt->get_name(), opt_req->get_name());
7328  // Excludes
7329  for(const Option *opt_ex : opt->excludes_)
7330  if(opt->count() > 0 && opt_ex->count() != 0)
7331  throw ExcludesError(opt->get_name(), opt_ex->get_name());
7332  }
7333  // check for the required number of subcommands
7334  if(require_subcommand_min_ > 0) {
7335  auto selected_subcommands = get_subcommands();
7336  if(require_subcommand_min_ > selected_subcommands.size())
7337  throw RequiredError::Subcommand(require_subcommand_min_);
7338  }
7339 
7340  // Max error cannot occur, the extra subcommand will parse as an ExtrasError or a remaining item.
7341 
7342  // run this loop to check how many unnamed subcommands were actually used since they are considered options
7343  // from the perspective of an App
7344  for(App_p &sub : subcommands_) {
7345  if(sub->disabled_)
7346  continue;
7347  if(sub->name_.empty() && sub->count_all() > 0) {
7348  ++used_options;
7349  }
7350  }
7351 
7352  if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {
7353  auto option_list = detail::join(options_, [this](const Option_p &ptr) {
7354  if(ptr.get() == help_ptr_ || ptr.get() == help_all_ptr_) {
7355  return std::string{};
7356  }
7357  return ptr->get_name(false, true);
7358  });
7359 
7360  auto subc_list = get_subcommands([](App *app) { return ((app->get_name().empty()) && (!app->disabled_)); });
7361  if(!subc_list.empty()) {
7362  option_list += "," + detail::join(subc_list, [](const App *app) { return app->get_display_name(); });
7363  }
7364  throw RequiredError::Option(require_option_min_, require_option_max_, used_options, option_list);
7365  }
7366 
7367  // now process the requirements for subcommands if needed
7368  for(App_p &sub : subcommands_) {
7369  if(sub->disabled_)
7370  continue;
7371  if(sub->name_.empty() && sub->required_ == false) {
7372  if(sub->count_all() == 0) {
7373  if(require_option_min_ > 0 && require_option_min_ <= used_options) {
7374  continue;
7375  // if we have met the requirement and there is nothing in this option group skip checking
7376  // requirements
7377  }
7378  if(require_option_max_ > 0 && used_options >= require_option_min_) {
7379  continue;
7380  // if we have met the requirement and there is nothing in this option group skip checking
7381  // requirements
7382  }
7383  }
7384  }
7385  if(sub->count() > 0 || sub->name_.empty()) {
7386  sub->_process_requirements();
7387  }
7388 
7389  if(sub->required_ && sub->count_all() == 0) {
7390  throw(CLI::RequiredError(sub->get_display_name()));
7391  }
7392  }
7393  }
7394 
7396  void _process() {
7397  CLI::FileError fe("ne");
7398  bool caught_error{false};
7399  try {
7400  // the config file might generate a FileError but that should not be processed until later in the process
7401  // to allow for help, version and other errors to generate first.
7402  _process_config_file();
7403  // process env shouldn't throw but no reason to process it if config generated an error
7404  _process_env();
7405  } catch(const CLI::FileError &fe2) {
7406  fe = fe2;
7407  caught_error = true;
7408  }
7409  // callbacks and help_flags can generate exceptions which should take priority over the config file error if one
7410  // exists
7411  _process_callbacks();
7412  _process_help_flags();
7413 
7414  if(caught_error) {
7415  throw CLI::FileError(std::move(fe));
7416  }
7417 
7418  _process_requirements();
7419  }
7420 
7423  if(!(allow_extras_ || prefix_command_)) {
7424  std::size_t num_left_over = remaining_size();
7425  if(num_left_over > 0) {
7426  throw ExtrasError(name_, remaining(false));
7427  }
7428  }
7429 
7430  for(App_p &sub : subcommands_) {
7431  if(sub->count() > 0)
7432  sub->_process_extras();
7433  }
7434  }
7435 
7438  void _process_extras(std::vector<std::string> &args) {
7439  if(!(allow_extras_ || prefix_command_)) {
7440  std::size_t num_left_over = remaining_size();
7441  if(num_left_over > 0) {
7442  args = remaining(false);
7443  throw ExtrasError(name_, args);
7444  }
7445  }
7446 
7447  for(App_p &sub : subcommands_) {
7448  if(sub->count() > 0)
7449  sub->_process_extras(args);
7450  }
7451  }
7452 
7455  ++parsed_;
7456  for(App_p &sub : subcommands_) {
7457  if(sub->get_name().empty())
7458  sub->increment_parsed();
7459  }
7460  }
7462  void _parse(std::vector<std::string> &args) {
7463  increment_parsed();
7464  _trigger_pre_parse(args.size());
7465  bool positional_only = false;
7466 
7467  while(!args.empty()) {
7468  if(!_parse_single(args, positional_only)) {
7469  break;
7470  }
7471  }
7472 
7473  if(parent_ == nullptr) {
7474  _process();
7475 
7476  // Throw error if any items are left over (depending on settings)
7477  _process_extras(args);
7478 
7479  // Convert missing (pairs) to extras (string only) ready for processing in another app
7480  args = remaining_for_passthrough(false);
7481  } else if(parse_complete_callback_) {
7482  _process_env();
7483  _process_callbacks();
7484  _process_help_flags();
7485  _process_requirements();
7486  run_callback(false, true);
7487  }
7488  }
7489 
7491  void _parse(std::vector<std::string> &&args) {
7492  // this can only be called by the top level in which case parent == nullptr by definition
7493  // operation is simplified
7494  increment_parsed();
7495  _trigger_pre_parse(args.size());
7496  bool positional_only = false;
7497 
7498  while(!args.empty()) {
7499  _parse_single(args, positional_only);
7500  }
7501  _process();
7502 
7503  // Throw error if any items are left over (depending on settings)
7504  _process_extras();
7505  }
7506 
7511  void _parse_config(const std::vector<ConfigItem> &args) {
7512  for(const ConfigItem &item : args) {
7513  if(!_parse_single_config(item) && allow_config_extras_ == config_extras_mode::error)
7514  throw ConfigError::Extras(item.fullname());
7515  }
7516  }
7517 
7519  bool _parse_single_config(const ConfigItem &item, std::size_t level = 0) {
7520  if(level < item.parents.size()) {
7521  try {
7522  auto subcom = get_subcommand(item.parents.at(level));
7523  auto result = subcom->_parse_single_config(item, level + 1);
7524 
7525  return result;
7526  } catch(const OptionNotFound &) {
7527  return false;
7528  }
7529  }
7530  // check for section open
7531  if(item.name == "++") {
7532  if(configurable_) {
7533  increment_parsed();
7534  _trigger_pre_parse(2);
7535  if(parent_ != nullptr) {
7536  parent_->parsed_subcommands_.push_back(this);
7537  }
7538  }
7539  return true;
7540  }
7541  // check for section close
7542  if(item.name == "--") {
7543  if(configurable_) {
7544  _process_callbacks();
7545  _process_requirements();
7546  run_callback();
7547  }
7548  return true;
7549  }
7550  Option *op = get_option_no_throw("--" + item.name);
7551  if(op == nullptr) {
7552  if(item.name.size() == 1) {
7553  op = get_option_no_throw("-" + item.name);
7554  }
7555  }
7556  if(op == nullptr) {
7557  op = get_option_no_throw(item.name);
7558  }
7559  if(op == nullptr) {
7560  // If the option was not present
7561  if(get_allow_config_extras() == config_extras_mode::capture)
7562  // Should we worry about classifying the extras properly?
7563  missing_.emplace_back(detail::Classifier::NONE, item.fullname());
7564  return false;
7565  }
7566 
7567  if(!op->get_configurable())
7568  throw ConfigError::NotConfigurable(item.fullname());
7569 
7570  if(op->empty()) {
7571  // Flag parsing
7572  if(op->get_expected_min() == 0) {
7573  auto res = config_formatter_->to_flag(item);
7574  res = op->get_flag_value(item.name, res);
7575 
7576  op->add_result(res);
7577 
7578  } else {
7579  op->add_result(item.inputs);
7580  op->run_callback();
7581  }
7582  }
7583 
7584  return true;
7585  }
7586 
7589  bool _parse_single(std::vector<std::string> &args, bool &positional_only) {
7590  bool retval = true;
7591  detail::Classifier classifier = positional_only ? detail::Classifier::NONE : _recognize(args.back());
7592  switch(classifier) {
7593  case detail::Classifier::POSITIONAL_MARK:
7594  args.pop_back();
7595  positional_only = true;
7596  if((!_has_remaining_positionals()) && (parent_ != nullptr)) {
7597  retval = false;
7598  } else {
7599  _move_to_missing(classifier, "--");
7600  }
7601  break;
7602  case detail::Classifier::SUBCOMMAND_TERMINATOR:
7603  // treat this like a positional mark if in the parent app
7604  args.pop_back();
7605  retval = false;
7606  break;
7607  case detail::Classifier::SUBCOMMAND:
7608  retval = _parse_subcommand(args);
7609  break;
7610  case detail::Classifier::LONG:
7611  case detail::Classifier::SHORT:
7612  case detail::Classifier::WINDOWS_STYLE:
7613  // If already parsed a subcommand, don't accept options_
7614  _parse_arg(args, classifier);
7615  break;
7616  case detail::Classifier::NONE:
7617  // Probably a positional or something for a parent (sub)command
7618  retval = _parse_positional(args, false);
7619  if(retval && positionals_at_end_) {
7620  positional_only = true;
7621  }
7622  break;
7623  // LCOV_EXCL_START
7624  default:
7625  throw HorribleError("unrecognized classifier (you should not see this!)");
7626  // LCOV_EXCL_STOP
7627  }
7628  return retval;
7629  }
7630 
7632  std::size_t _count_remaining_positionals(bool required_only = false) const {
7633  std::size_t retval = 0;
7634  for(const Option_p &opt : options_) {
7635  if(opt->get_positional() && (!required_only || opt->get_required())) {
7636  if(opt->get_items_expected_min() > 0 &&
7637  static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
7638  retval += static_cast<std::size_t>(opt->get_items_expected_min()) - opt->count();
7639  }
7640  }
7641  }
7642  return retval;
7643  }
7644 
7647  for(const Option_p &opt : options_) {
7648  if(opt->get_positional() && ((static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {
7649  return true;
7650  }
7651  }
7652 
7653  return false;
7654  }
7655 
7659  bool _parse_positional(std::vector<std::string> &args, bool haltOnSubcommand) {
7660 
7661  const std::string &positional = args.back();
7662 
7663  if(positionals_at_end_) {
7664  // deal with the case of required arguments at the end which should take precedence over other arguments
7665  auto arg_rem = args.size();
7666  auto remreq = _count_remaining_positionals(true);
7667  if(arg_rem <= remreq) {
7668  for(const Option_p &opt : options_) {
7669  if(opt->get_positional() && opt->required_) {
7670  if(static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
7671  if(validate_positionals_) {
7672  std::string pos = positional;
7673  pos = opt->_validate(pos, 0);
7674  if(!pos.empty()) {
7675  continue;
7676  }
7677  }
7678  opt->add_result(positional);
7679  parse_order_.push_back(opt.get());
7680  args.pop_back();
7681  return true;
7682  }
7683  }
7684  }
7685  }
7686  }
7687  for(const Option_p &opt : options_) {
7688  // Eat options, one by one, until done
7689  if(opt->get_positional() &&
7690  (static_cast<int>(opt->count()) < opt->get_items_expected_min() || opt->get_allow_extra_args())) {
7691  if(validate_positionals_) {
7692  std::string pos = positional;
7693  pos = opt->_validate(pos, 0);
7694  if(!pos.empty()) {
7695  continue;
7696  }
7697  }
7698  opt->add_result(positional);
7699  parse_order_.push_back(opt.get());
7700  args.pop_back();
7701  return true;
7702  }
7703  }
7704 
7705  for(auto &subc : subcommands_) {
7706  if((subc->name_.empty()) && (!subc->disabled_)) {
7707  if(subc->_parse_positional(args, false)) {
7708  if(!subc->pre_parse_called_) {
7709  subc->_trigger_pre_parse(args.size());
7710  }
7711  return true;
7712  }
7713  }
7714  }
7715  // let the parent deal with it if possible
7716  if(parent_ != nullptr && fallthrough_)
7717  return _get_fallthrough_parent()->_parse_positional(args, static_cast<bool>(parse_complete_callback_));
7718 
7720  auto com = _find_subcommand(args.back(), true, false);
7721  if(com != nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {
7722  if(haltOnSubcommand) {
7723  return false;
7724  }
7725  args.pop_back();
7726  com->_parse(args);
7727  return true;
7728  }
7731  auto parent_app = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
7732  com = parent_app->_find_subcommand(args.back(), true, false);
7733  if(com != nullptr && (com->parent_->require_subcommand_max_ == 0 ||
7734  com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
7735  return false;
7736  }
7737 
7738  if(positionals_at_end_) {
7739  throw CLI::ExtrasError(name_, args);
7740  }
7742  if(parent_ != nullptr && name_.empty()) {
7743  return false;
7744  }
7746  _move_to_missing(detail::Classifier::NONE, positional);
7747  args.pop_back();
7748  if(prefix_command_) {
7749  while(!args.empty()) {
7750  _move_to_missing(detail::Classifier::NONE, args.back());
7751  args.pop_back();
7752  }
7753  }
7754 
7755  return true;
7756  }
7757 
7760  App *_find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept {
7761  for(const App_p &com : subcommands_) {
7762  if(com->disabled_ && ignore_disabled)
7763  continue;
7764  if(com->get_name().empty()) {
7765  auto subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);
7766  if(subc != nullptr) {
7767  return subc;
7768  }
7769  }
7770  if(com->check_name(subc_name)) {
7771  if((!*com) || !ignore_used)
7772  return com.get();
7773  }
7774  }
7775  return nullptr;
7776  }
7777 
7782  bool _parse_subcommand(std::vector<std::string> &args) {
7783  if(_count_remaining_positionals(/* required */ true) > 0) {
7784  _parse_positional(args, false);
7785  return true;
7786  }
7787  auto com = _find_subcommand(args.back(), true, true);
7788  if(com != nullptr) {
7789  args.pop_back();
7790  if(!com->silent_) {
7791  parsed_subcommands_.push_back(com);
7792  }
7793  com->_parse(args);
7794  auto parent_app = com->parent_;
7795  while(parent_app != this) {
7796  parent_app->_trigger_pre_parse(args.size());
7797  if(!com->silent_) {
7798  parent_app->parsed_subcommands_.push_back(com);
7799  }
7800  parent_app = parent_app->parent_;
7801  }
7802  return true;
7803  }
7804 
7805  if(parent_ == nullptr)
7806  throw HorribleError("Subcommand " + args.back() + " missing");
7807  return false;
7808  }
7809 
7812  bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {
7813 
7814  std::string current = args.back();
7815 
7816  std::string arg_name;
7817  std::string value;
7818  std::string rest;
7819 
7820  switch(current_type) {
7821  case detail::Classifier::LONG:
7822  if(!detail::split_long(current, arg_name, value))
7823  throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
7824  break;
7825  case detail::Classifier::SHORT:
7826  if(!detail::split_short(current, arg_name, rest))
7827  throw HorribleError("Short parsed but missing! You should not see this");
7828  break;
7829  case detail::Classifier::WINDOWS_STYLE:
7830  if(!detail::split_windows_style(current, arg_name, value))
7831  throw HorribleError("windows option parsed but missing! You should not see this");
7832  break;
7833  case detail::Classifier::SUBCOMMAND:
7834  case detail::Classifier::SUBCOMMAND_TERMINATOR:
7835  case detail::Classifier::POSITIONAL_MARK:
7836  case detail::Classifier::NONE:
7837  default:
7838  throw HorribleError("parsing got called with invalid option! You should not see this");
7839  }
7840 
7841  auto op_ptr =
7842  std::find_if(std::begin(options_), std::end(options_), [arg_name, current_type](const Option_p &opt) {
7843  if(current_type == detail::Classifier::LONG)
7844  return opt->check_lname(arg_name);
7845  if(current_type == detail::Classifier::SHORT)
7846  return opt->check_sname(arg_name);
7847  // this will only get called for detail::Classifier::WINDOWS_STYLE
7848  return opt->check_lname(arg_name) || opt->check_sname(arg_name);
7849  });
7850 
7851  // Option not found
7852  if(op_ptr == std::end(options_)) {
7853  for(auto &subc : subcommands_) {
7854  if(subc->name_.empty() && !subc->disabled_) {
7855  if(subc->_parse_arg(args, current_type)) {
7856  if(!subc->pre_parse_called_) {
7857  subc->_trigger_pre_parse(args.size());
7858  }
7859  return true;
7860  }
7861  }
7862  }
7863  // If a subcommand, try the master command
7864  if(parent_ != nullptr && fallthrough_)
7865  return _get_fallthrough_parent()->_parse_arg(args, current_type);
7866  // don't capture missing if this is a nameless subcommand
7867  if(parent_ != nullptr && name_.empty()) {
7868  return false;
7869  }
7870  // Otherwise, add to missing
7871  args.pop_back();
7872  _move_to_missing(current_type, current);
7873  return true;
7874  }
7875 
7876  args.pop_back();
7877 
7878  // Get a reference to the pointer to make syntax bearable
7879  Option_p &op = *op_ptr;
7881  if(op->get_inject_separator()) {
7882  if(!op->results().empty() && !op->results().back().empty()) {
7883  op->add_result(std::string{});
7884  }
7885  }
7886  int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
7887  int max_num = op->get_items_expected_max();
7888  // check container like options to limit the argument size to a single type if the allow_extra_flags argument is
7889  // set. 16 is somewhat arbitrary (needs to be at least 4)
7890  if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
7891  auto tmax = op->get_type_size_max();
7892  max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
7893  }
7894  // Make sure we always eat the minimum for unlimited vectors
7895  int collected = 0; // total number of arguments collected
7896  int result_count = 0; // local variable for number of results in a single arg string
7897  // deal with purely flag like things
7898  if(max_num == 0) {
7899  auto res = op->get_flag_value(arg_name, value);
7900  op->add_result(res);
7901  parse_order_.push_back(op.get());
7902  } else if(!value.empty()) { // --this=value
7903  op->add_result(value, result_count);
7904  parse_order_.push_back(op.get());
7905  collected += result_count;
7906  // -Trest
7907  } else if(!rest.empty()) {
7908  op->add_result(rest, result_count);
7909  parse_order_.push_back(op.get());
7910  rest = "";
7911  collected += result_count;
7912  }
7913 
7914  // gather the minimum number of arguments
7915  while(min_num > collected && !args.empty()) {
7916  std::string current_ = args.back();
7917  args.pop_back();
7918  op->add_result(current_, result_count);
7919  parse_order_.push_back(op.get());
7920  collected += result_count;
7921  }
7922 
7923  if(min_num > collected) { // if we have run out of arguments and the minimum was not met
7924  throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
7925  }
7926 
7927  if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments
7928  auto remreqpos = _count_remaining_positionals(true);
7929  // we have met the minimum now optionally check up to the maximum
7930  while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
7931  _recognize(args.back(), false) == detail::Classifier::NONE) {
7932  // If any required positionals remain, don't keep eating
7933  if(remreqpos >= args.size()) {
7934  break;
7935  }
7936 
7937  op->add_result(args.back(), result_count);
7938  parse_order_.push_back(op.get());
7939  args.pop_back();
7940  collected += result_count;
7941  }
7942 
7943  // Allow -- to end an unlimited list and "eat" it
7944  if(!args.empty() && _recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
7945  args.pop_back();
7946  // optional flag that didn't receive anything now get the default value
7947  if(min_num == 0 && max_num > 0 && collected == 0) {
7948  auto res = op->get_flag_value(arg_name, std::string{});
7949  op->add_result(res);
7950  parse_order_.push_back(op.get());
7951  }
7952  }
7953 
7954  // if we only partially completed a type then add an empty string for later processing
7955  if(min_num > 0 && op->get_type_size_max() != min_num && (collected % op->get_type_size_max()) != 0) {
7956  op->add_result(std::string{});
7957  }
7958 
7959  if(!rest.empty()) {
7960  rest = "-" + rest;
7961  args.push_back(rest);
7962  }
7963  return true;
7964  }
7965 
7967  void _trigger_pre_parse(std::size_t remaining_args) {
7968  if(!pre_parse_called_) {
7969  pre_parse_called_ = true;
7970  if(pre_parse_callback_) {
7971  pre_parse_callback_(remaining_args);
7972  }
7973  } else if(immediate_callback_) {
7974  if(!name_.empty()) {
7975  auto pcnt = parsed_;
7976  auto extras = std::move(missing_);
7977  clear();
7978  parsed_ = pcnt;
7979  pre_parse_called_ = true;
7980  missing_ = std::move(extras);
7981  }
7982  }
7983  }
7984 
7987  if(parent_ == nullptr) {
7988  throw(HorribleError("No Valid parent"));
7989  }
7990  auto fallthrough_parent = parent_;
7991  while((fallthrough_parent->parent_ != nullptr) && (fallthrough_parent->get_name().empty())) {
7992  fallthrough_parent = fallthrough_parent->parent_;
7993  }
7994  return fallthrough_parent;
7995  }
7996 
7998  const std::string &_compare_subcommand_names(const App &subcom, const App &base) const {
7999  static const std::string estring;
8000  if(subcom.disabled_) {
8001  return estring;
8002  }
8003  for(auto &subc : base.subcommands_) {
8004  if(subc.get() != &subcom) {
8005  if(subc->disabled_) {
8006  continue;
8007  }
8008  if(!subcom.get_name().empty()) {
8009  if(subc->check_name(subcom.get_name())) {
8010  return subcom.get_name();
8011  }
8012  }
8013  if(!subc->get_name().empty()) {
8014  if(subcom.check_name(subc->get_name())) {
8015  return subc->get_name();
8016  }
8017  }
8018  for(const auto &les : subcom.aliases_) {
8019  if(subc->check_name(les)) {
8020  return les;
8021  }
8022  }
8023  // this loop is needed in case of ignore_underscore or ignore_case on one but not the other
8024  for(const auto &les : subc->aliases_) {
8025  if(subcom.check_name(les)) {
8026  return les;
8027  }
8028  }
8029  // if the subcommand is an option group we need to check deeper
8030  if(subc->get_name().empty()) {
8031  auto &cmpres = _compare_subcommand_names(subcom, *subc);
8032  if(!cmpres.empty()) {
8033  return cmpres;
8034  }
8035  }
8036  // if the test subcommand is an option group we need to check deeper
8037  if(subcom.get_name().empty()) {
8038  auto &cmpres = _compare_subcommand_names(*subc, subcom);
8039  if(!cmpres.empty()) {
8040  return cmpres;
8041  }
8042  }
8043  }
8044  }
8045  return estring;
8046  }
8048  void _move_to_missing(detail::Classifier val_type, const std::string &val) {
8049  if(allow_extras_ || subcommands_.empty()) {
8050  missing_.emplace_back(val_type, val);
8051  return;
8052  }
8053  // allow extra arguments to be places in an option group if it is allowed there
8054  for(auto &subc : subcommands_) {
8055  if(subc->name_.empty() && subc->allow_extras_) {
8056  subc->missing_.emplace_back(val_type, val);
8057  return;
8058  }
8059  }
8060  // if we haven't found any place to put them yet put them in missing
8061  missing_.emplace_back(val_type, val);
8062  }
8063 
8064  public:
8066  void _move_option(Option *opt, App *app) {
8067  if(opt == nullptr) {
8068  throw OptionNotFound("the option is NULL");
8069  }
8070  // verify that the give app is actually a subcommand
8071  bool found = false;
8072  for(auto &subc : subcommands_) {
8073  if(app == subc.get()) {
8074  found = true;
8075  }
8076  }
8077  if(!found) {
8078  throw OptionNotFound("The Given app is not a subcommand");
8079  }
8080 
8081  if((help_ptr_ == opt) || (help_all_ptr_ == opt))
8082  throw OptionAlreadyAdded("cannot move help options");
8083 
8084  if(config_ptr_ == opt)
8085  throw OptionAlreadyAdded("cannot move config file options");
8086 
8087  auto iterator =
8088  std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
8089  if(iterator != std::end(options_)) {
8090  const auto &opt_p = *iterator;
8091  if(std::find_if(std::begin(app->options_), std::end(app->options_), [&opt_p](const Option_p &v) {
8092  return (*v == *opt_p);
8093  }) == std::end(app->options_)) {
8094  // only erase after the insertion was successful
8095  app->options_.push_back(std::move(*iterator));
8096  options_.erase(iterator);
8097  } else {
8098  throw OptionAlreadyAdded("option was not located: " + opt->get_name());
8099  }
8100  } else {
8101  throw OptionNotFound("could not locate the given Option");
8102  }
8103  }
8104 }; // namespace CLI
8105 
8107 class Option_group : public App {
8108  public:
8109  Option_group(std::string group_description, std::string group_name, App *parent)
8110  : App(std::move(group_description), "", parent) {
8111  group(group_name);
8112  // option groups should have automatic fallthrough
8113  }
8114  using App::add_option;
8117  if(get_parent() == nullptr) {
8118  throw OptionNotFound("Unable to locate the specified option");
8119  }
8120  get_parent()->_move_option(opt, this);
8121  return opt;
8122  }
8124  void add_options(Option *opt) { add_option(opt); }
8126  template <typename... Args> void add_options(Option *opt, Args... args) {
8127  add_option(opt);
8128  add_options(args...);
8129  }
8130  using App::add_subcommand;
8132  App *add_subcommand(App *subcom) {
8133  App_p subc = subcom->get_parent()->get_subcommand_ptr(subcom);
8134  subc->get_parent()->remove_subcommand(subcom);
8135  add_subcommand(std::move(subc));
8136  return subcom;
8137  }
8138 };
8140 inline void TriggerOn(App *trigger_app, App *app_to_enable) {
8141  app_to_enable->enabled_by_default(false);
8142  app_to_enable->disabled_by_default();
8143  trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(false); });
8144 }
8145 
8147 inline void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {
8148  for(auto &app : apps_to_enable) {
8149  app->enabled_by_default(false);
8150  app->disabled_by_default();
8151  }
8152 
8153  trigger_app->preparse_callback([apps_to_enable](std::size_t) {
8154  for(auto &app : apps_to_enable) {
8155  app->disabled(false);
8156  }
8157  });
8158 }
8159 
8161 inline void TriggerOff(App *trigger_app, App *app_to_enable) {
8162  app_to_enable->disabled_by_default(false);
8163  app_to_enable->enabled_by_default();
8164  trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });
8165 }
8166 
8168 inline void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {
8169  for(auto &app : apps_to_enable) {
8170  app->disabled_by_default(false);
8171  app->enabled_by_default();
8172  }
8173 
8174  trigger_app->preparse_callback([apps_to_enable](std::size_t) {
8175  for(auto &app : apps_to_enable) {
8176  app->disabled();
8177  }
8178  });
8179 }
8180 
8182 inline void deprecate_option(Option *opt, const std::string &replacement = "") {
8183  Validator deprecate_warning{[opt, replacement](std::string &) {
8184  std::cout << opt->get_name() << " is deprecated please use '" << replacement
8185  << "' instead\n";
8186  return std::string();
8187  },
8188  "DEPRECATED"};
8189  deprecate_warning.application_index(0);
8190  opt->check(deprecate_warning);
8191  if(!replacement.empty()) {
8192  opt->description(opt->get_description() + " DEPRECATED: please use '" + replacement + "' instead");
8193  }
8194 }
8195 
8197 inline void deprecate_option(App *app, const std::string &option_name, const std::string &replacement = "") {
8198  auto opt = app->get_option(option_name);
8199  deprecate_option(opt, replacement);
8200 }
8201 
8203 inline void deprecate_option(App &app, const std::string &option_name, const std::string &replacement = "") {
8204  auto opt = app.get_option(option_name);
8205  deprecate_option(opt, replacement);
8206 }
8207 
8209 inline void retire_option(App *app, Option *opt) {
8210  App temp;
8211  auto option_copy = temp.add_option(opt->get_name(false, true))
8212  ->type_size(opt->get_type_size_min(), opt->get_type_size_max())
8213  ->expected(opt->get_expected_min(), opt->get_expected_max())
8214  ->allow_extra_args(opt->get_allow_extra_args());
8215 
8216  app->remove_option(opt);
8217  auto opt2 = app->add_option(option_copy->get_name(false, true), "option has been retired and has no effect")
8218  ->type_name("RETIRED")
8219  ->default_str("RETIRED")
8220  ->type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())
8221  ->expected(option_copy->get_expected_min(), option_copy->get_expected_max())
8222  ->allow_extra_args(option_copy->get_allow_extra_args());
8223 
8224  Validator retired_warning{[opt2](std::string &) {
8225  std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
8226  return std::string();
8227  },
8228  ""};
8229  retired_warning.application_index(0);
8230  opt2->check(retired_warning);
8231 }
8232 
8234 inline void retire_option(App &app, Option *opt) { retire_option(&app, opt); }
8235 
8237 inline void retire_option(App *app, const std::string &option_name) {
8238 
8239  auto opt = app->get_option_no_throw(option_name);
8240  if(opt != nullptr) {
8241  retire_option(app, opt);
8242  return;
8243  }
8244  auto opt2 = app->add_option(option_name, "option has been retired and has no effect")
8245  ->type_name("RETIRED")
8246  ->expected(0, 1)
8247  ->default_str("RETIRED");
8248  Validator retired_warning{[opt2](std::string &) {
8249  std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
8250  return std::string();
8251  },
8252  ""};
8253  retired_warning.application_index(0);
8254  opt2->check(retired_warning);
8255 }
8256 
8258 inline void retire_option(App &app, const std::string &option_name) { retire_option(&app, option_name); }
8259 
8260 namespace FailureMessage {
8261 
8263 inline std::string simple(const App *app, const Error &e) {
8264  std::string header = std::string(e.what()) + "\n";
8265  std::vector<std::string> names;
8266 
8267  // Collect names
8268  if(app->get_help_ptr() != nullptr)
8269  names.push_back(app->get_help_ptr()->get_name());
8270 
8271  if(app->get_help_all_ptr() != nullptr)
8272  names.push_back(app->get_help_all_ptr()->get_name());
8273 
8274  // If any names found, suggest those
8275  if(!names.empty())
8276  header += "Run with " + detail::join(names, " or ") + " for more information.\n";
8277 
8278  return header;
8279 }
8280 
8282 inline std::string help(const App *app, const Error &e) {
8283  std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
8284  header += app->help();
8285  return header;
8286 }
8287 
8288 } // namespace FailureMessage
8289 
8290 namespace detail {
8292 struct AppFriend {
8293 #ifdef CLI11_CPP14
8294 
8296  template <typename... Args> static decltype(auto) parse_arg(App *app, Args &&... args) {
8297  return app->_parse_arg(std::forward<Args>(args)...);
8298  }
8299 
8301  template <typename... Args> static decltype(auto) parse_subcommand(App *app, Args &&... args) {
8302  return app->_parse_subcommand(std::forward<Args>(args)...);
8303  }
8304 #else
8305  template <typename... Args>
8307  static auto parse_arg(App *app, Args &&... args) ->
8308  typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>::type {
8309  return app->_parse_arg(std::forward<Args>(args)...);
8310  }
8311 
8313  template <typename... Args>
8314  static auto parse_subcommand(App *app, Args &&... args) ->
8315  typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
8316  return app->_parse_subcommand(std::forward<Args>(args)...);
8317  }
8318 #endif
8319  static App *get_fallthrough_parent(App *app) { return app->_get_fallthrough_parent(); }
8321 };
8322 } // namespace detail
8323 
8324 
8325 
8326 
8327 namespace detail {
8328 
8329 inline std::string convert_arg_for_ini(const std::string &arg, char stringQuote = '"', char characterQuote = '\'') {
8330  if(arg.empty()) {
8331  return std::string(2, stringQuote);
8332  }
8333  // some specifically supported strings
8334  if(arg == "true" || arg == "false" || arg == "nan" || arg == "inf") {
8335  return arg;
8336  }
8337  // floating point conversion can convert some hex codes, but don't try that here
8338  if(arg.compare(0, 2, "0x") != 0 && arg.compare(0, 2, "0X") != 0) {
8339  double val;
8340  if(detail::lexical_cast(arg, val)) {
8341  return arg;
8342  }
8343  }
8344  // just quote a single non numeric character
8345  if(arg.size() == 1) {
8346  return std::string(1, characterQuote) + arg + characterQuote;
8347  }
8348  // handle hex, binary or octal arguments
8349  if(arg.front() == '0') {
8350  if(arg[1] == 'x') {
8351  if(std::all_of(arg.begin() + 2, arg.end(), [](char x) {
8352  return (x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f');
8353  })) {
8354  return arg;
8355  }
8356  } else if(arg[1] == 'o') {
8357  if(std::all_of(arg.begin() + 2, arg.end(), [](char x) { return (x >= '0' && x <= '7'); })) {
8358  return arg;
8359  }
8360  } else if(arg[1] == 'b') {
8361  if(std::all_of(arg.begin() + 2, arg.end(), [](char x) { return (x == '0' || x == '1'); })) {
8362  return arg;
8363  }
8364  }
8365  }
8366  if(arg.find_first_of(stringQuote) == std::string::npos) {
8367  return std::string(1, stringQuote) + arg + stringQuote;
8368  } else {
8369  return characterQuote + arg + characterQuote;
8370  }
8371 }
8372 
8374 inline std::string ini_join(const std::vector<std::string> &args,
8375  char sepChar = ',',
8376  char arrayStart = '[',
8377  char arrayEnd = ']',
8378  char stringQuote = '"',
8379  char characterQuote = '\'') {
8380  std::string joined;
8381  if(args.size() > 1 && arrayStart != '\0') {
8382  joined.push_back(arrayStart);
8383  }
8384  std::size_t start = 0;
8385  for(const auto &arg : args) {
8386  if(start++ > 0) {
8387  joined.push_back(sepChar);
8388  if(isspace(sepChar) == 0) {
8389  joined.push_back(' ');
8390  }
8391  }
8392  joined.append(convert_arg_for_ini(arg, stringQuote, characterQuote));
8393  }
8394  if(args.size() > 1 && arrayEnd != '\0') {
8395  joined.push_back(arrayEnd);
8396  }
8397  return joined;
8398 }
8399 
8400 inline std::vector<std::string> generate_parents(const std::string &section, std::string &name) {
8401  std::vector<std::string> parents;
8402  if(detail::to_lower(section) != "default") {
8403  if(section.find('.') != std::string::npos) {
8404  parents = detail::split(section, '.');
8405  } else {
8406  parents = {section};
8407  }
8408  }
8409  if(name.find('.') != std::string::npos) {
8410  std::vector<std::string> plist = detail::split(name, '.');
8411  name = plist.back();
8412  detail::remove_quotes(name);
8413  plist.pop_back();
8414  parents.insert(parents.end(), plist.begin(), plist.end());
8415  }
8416 
8417  // clean up quotes on the parents
8418  for(auto &parent : parents) {
8419  detail::remove_quotes(parent);
8420  }
8421  return parents;
8422 }
8423 
8425 inline void checkParentSegments(std::vector<ConfigItem> &output, const std::string &currentSection) {
8426 
8427  std::string estring;
8428  auto parents = detail::generate_parents(currentSection, estring);
8429  if(!output.empty() && output.back().name == "--") {
8430  std::size_t msize = (parents.size() > 1U) ? parents.size() : 2;
8431  while(output.back().parents.size() >= msize) {
8432  output.push_back(output.back());
8433  output.back().parents.pop_back();
8434  }
8435 
8436  if(parents.size() > 1) {
8437  std::size_t common = 0;
8438  std::size_t mpair = (std::min)(output.back().parents.size(), parents.size() - 1);
8439  for(std::size_t ii = 0; ii < mpair; ++ii) {
8440  if(output.back().parents[ii] != parents[ii]) {
8441  break;
8442  }
8443  ++common;
8444  }
8445  if(common == mpair) {
8446  output.pop_back();
8447  } else {
8448  while(output.back().parents.size() > common + 1) {
8449  output.push_back(output.back());
8450  output.back().parents.pop_back();
8451  }
8452  }
8453  for(std::size_t ii = common; ii < parents.size() - 1; ++ii) {
8454  output.emplace_back();
8455  output.back().parents.assign(parents.begin(), parents.begin() + static_cast<std::ptrdiff_t>(ii) + 1);
8456  output.back().name = "++";
8457  }
8458  }
8459  } else if(parents.size() > 1) {
8460  for(std::size_t ii = 0; ii < parents.size() - 1; ++ii) {
8461  output.emplace_back();
8462  output.back().parents.assign(parents.begin(), parents.begin() + static_cast<std::ptrdiff_t>(ii) + 1);
8463  output.back().name = "++";
8464  }
8465  }
8466 
8467  // insert a section end which is just an empty items_buffer
8468  output.emplace_back();
8469  output.back().parents = std::move(parents);
8470  output.back().name = "++";
8471 }
8472 } // namespace detail
8473 
8474 inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) const {
8475  std::string line;
8476  std::string section = "default";
8477 
8478  std::vector<ConfigItem> output;
8479  bool isDefaultArray = (arrayStart == '[' && arrayEnd == ']' && arraySeparator == ',');
8480  bool isINIArray = (arrayStart == '\0' || arrayStart == ' ') && arrayStart == arrayEnd;
8481  char aStart = (isINIArray) ? '[' : arrayStart;
8482  char aEnd = (isINIArray) ? ']' : arrayEnd;
8483  char aSep = (isINIArray && arraySeparator == ' ') ? ',' : arraySeparator;
8484 
8485  while(getline(input, line)) {
8486  std::vector<std::string> items_buffer;
8487  std::string name;
8488 
8489  detail::trim(line);
8490  std::size_t len = line.length();
8491  if(len > 1 && line.front() == '[' && line.back() == ']') {
8492  if(section != "default") {
8493  // insert a section end which is just an empty items_buffer
8494  output.emplace_back();
8495  output.back().parents = detail::generate_parents(section, name);
8496  output.back().name = "--";
8497  }
8498  section = line.substr(1, len - 2);
8499  // deal with double brackets for TOML
8500  if(section.size() > 1 && section.front() == '[' && section.back() == ']') {
8501  section = section.substr(1, section.size() - 2);
8502  }
8503  if(detail::to_lower(section) == "default") {
8504  section = "default";
8505  } else {
8506  detail::checkParentSegments(output, section);
8507  }
8508  continue;
8509  }
8510  if(len == 0) {
8511  continue;
8512  }
8513  // comment lines
8514  if(line.front() == ';' || line.front() == '#' || line.front() == commentChar) {
8515  continue;
8516  }
8517 
8518  // Find = in string, split and recombine
8519  auto pos = line.find(valueDelimiter);
8520  if(pos != std::string::npos) {
8521  name = detail::trim_copy(line.substr(0, pos));
8522  std::string item = detail::trim_copy(line.substr(pos + 1));
8523  if(item.size() > 1 && item.front() == aStart) {
8524  for(std::string multiline; item.back() != aEnd && std::getline(input, multiline);) {
8525  detail::trim(multiline);
8526  item += multiline;
8527  }
8528  items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
8529  } else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
8530  items_buffer = detail::split_up(item, aSep);
8531  } else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) {
8532  items_buffer = detail::split_up(item);
8533  } else {
8534  items_buffer = {item};
8535  }
8536  } else {
8537  name = detail::trim_copy(line);
8538  items_buffer = {"true"};
8539  }
8540  if(name.find('.') == std::string::npos) {
8541  detail::remove_quotes(name);
8542  }
8543  // clean up quotes on the items
8544  for(auto &it : items_buffer) {
8545  detail::remove_quotes(it);
8546  }
8547 
8548  std::vector<std::string> parents = detail::generate_parents(section, name);
8549 
8550  if(!output.empty() && name == output.back().name && parents == output.back().parents) {
8551  output.back().inputs.insert(output.back().inputs.end(), items_buffer.begin(), items_buffer.end());
8552  } else {
8553  output.emplace_back();
8554  output.back().parents = std::move(parents);
8555  output.back().name = std::move(name);
8556  output.back().inputs = std::move(items_buffer);
8557  }
8558  }
8559  if(section != "default") {
8560  // insert a section end which is just an empty items_buffer
8561  std::string ename;
8562  output.emplace_back();
8563  output.back().parents = detail::generate_parents(section, ename);
8564  output.back().name = "--";
8565  while(output.back().parents.size() > 1) {
8566  output.push_back(output.back());
8567  output.back().parents.pop_back();
8568  }
8569  }
8570  return output;
8571 }
8572 
8573 inline std::string
8574 ConfigBase::to_config(const App *app, bool default_also, bool write_description, std::string prefix) const {
8575  std::stringstream out;
8576  std::string commentLead;
8577  commentLead.push_back(commentChar);
8578  commentLead.push_back(' ');
8579 
8580  std::vector<std::string> groups = app->get_groups();
8581  bool defaultUsed = false;
8582  groups.insert(groups.begin(), std::string("Options"));
8583  if(write_description && (app->get_configurable() || app->get_parent() == nullptr || app->get_name().empty())) {
8584  out << commentLead << detail::fix_newlines(commentLead, app->get_description()) << '\n';
8585  }
8586  for(auto &group : groups) {
8587  if(group == "Options" || group.empty()) {
8588  if(defaultUsed) {
8589  continue;
8590  }
8591  defaultUsed = true;
8592  }
8593  if(write_description && group != "Options" && !group.empty()) {
8594  out << '\n' << commentLead << group << " Options\n";
8595  }
8596  for(const Option *opt : app->get_options({})) {
8597 
8598  // Only process options that are configurable
8599  if(opt->get_configurable()) {
8600  if(opt->get_group() != group) {
8601  if(!(group == "Options" && opt->get_group().empty())) {
8602  continue;
8603  }
8604  }
8605  std::string name = prefix + opt->get_single_name();
8606  std::string value = detail::ini_join(
8607  opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote);
8608 
8609  if(value.empty() && default_also) {
8610  if(!opt->get_default_str().empty()) {
8611  value = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, characterQuote);
8612  } else if(opt->get_expected_min() == 0) {
8613  value = "false";
8614  } else if(opt->get_run_callback_for_default()) {
8615  value = "\"\""; // empty string default value
8616  }
8617  }
8618 
8619  if(!value.empty()) {
8620  if(write_description && opt->has_description()) {
8621  out << '\n';
8622  out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n';
8623  }
8624  out << name << valueDelimiter << value << '\n';
8625  }
8626  }
8627  }
8628  }
8629  auto subcommands = app->get_subcommands({});
8630  for(const App *subcom : subcommands) {
8631  if(subcom->get_name().empty()) {
8632  if(write_description && !subcom->get_group().empty()) {
8633  out << '\n' << commentLead << subcom->get_group() << " Options\n";
8634  }
8635  out << to_config(subcom, default_also, write_description, prefix);
8636  }
8637  }
8638 
8639  for(const App *subcom : subcommands) {
8640  if(!subcom->get_name().empty()) {
8641  if(subcom->get_configurable() && app->got_subcommand(subcom)) {
8642  if(!prefix.empty() || app->get_parent() == nullptr) {
8643  out << '[' << prefix << subcom->get_name() << "]\n";
8644  } else {
8645  std::string subname = app->get_name() + "." + subcom->get_name();
8646  auto p = app->get_parent();
8647  while(p->get_parent() != nullptr) {
8648  subname = p->get_name() + "." + subname;
8649  p = p->get_parent();
8650  }
8651  out << '[' << subname << "]\n";
8652  }
8653  out << to_config(subcom, default_also, write_description, "");
8654  } else {
8655  out << to_config(subcom, default_also, write_description, prefix + subcom->get_name() + ".");
8656  }
8657  }
8658  }
8659 
8660  return out.str();
8661 }
8662 
8663 
8664 
8665 
8666 inline std::string
8667 Formatter::make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const {
8668  std::stringstream out;
8669 
8670  out << "\n" << group << ":\n";
8671  for(const Option *opt : opts) {
8672  out << make_option(opt, is_positional);
8673  }
8674 
8675  return out.str();
8676 }
8677 
8678 inline std::string Formatter::make_positionals(const App *app) const {
8679  std::vector<const Option *> opts =
8680  app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); });
8681 
8682  if(opts.empty())
8683  return std::string();
8684 
8685  return make_group(get_label("Positionals"), true, opts);
8686 }
8687 
8688 inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
8689  std::stringstream out;
8690  std::vector<std::string> groups = app->get_groups();
8691 
8692  // Options
8693  for(const std::string &group : groups) {
8694  std::vector<const Option *> opts = app->get_options([app, mode, &group](const Option *opt) {
8695  return opt->get_group() == group // Must be in the right group
8696  && opt->nonpositional() // Must not be a positional
8697  && (mode != AppFormatMode::Sub // If mode is Sub, then
8698  || (app->get_help_ptr() != opt // Ignore help pointer
8699  && app->get_help_all_ptr() != opt)); // Ignore help all pointer
8700  });
8701  if(!group.empty() && !opts.empty()) {
8702  out << make_group(group, false, opts);
8703 
8704  if(group != groups.back())
8705  out << "\n";
8706  }
8707  }
8708 
8709  return out.str();
8710 }
8711 
8712 inline std::string Formatter::make_description(const App *app) const {
8713  std::string desc = app->get_description();
8714  auto min_options = app->get_require_option_min();
8715  auto max_options = app->get_require_option_max();
8716  if(app->get_required()) {
8717  desc += " REQUIRED ";
8718  }
8719  if((max_options == min_options) && (min_options > 0)) {
8720  if(min_options == 1) {
8721  desc += " \n[Exactly 1 of the following options is required]";
8722  } else {
8723  desc += " \n[Exactly " + std::to_string(min_options) + "options from the following list are required]";
8724  }
8725  } else if(max_options > 0) {
8726  if(min_options > 0) {
8727  desc += " \n[Between " + std::to_string(min_options) + " and " + std::to_string(max_options) +
8728  " of the follow options are required]";
8729  } else {
8730  desc += " \n[At most " + std::to_string(max_options) + " of the following options are allowed]";
8731  }
8732  } else if(min_options > 0) {
8733  desc += " \n[At least " + std::to_string(min_options) + " of the following options are required]";
8734  }
8735  return (!desc.empty()) ? desc + "\n" : std::string{};
8736 }
8737 
8738 inline std::string Formatter::make_usage(const App *app, std::string name) const {
8739  std::stringstream out;
8740 
8741  out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
8742 
8743  std::vector<std::string> groups = app->get_groups();
8744 
8745  // Print an Options badge if any options exist
8746  std::vector<const Option *> non_pos_options =
8747  app->get_options([](const Option *opt) { return opt->nonpositional(); });
8748  if(!non_pos_options.empty())
8749  out << " [" << get_label("OPTIONS") << "]";
8750 
8751  // Positionals need to be listed here
8752  std::vector<const Option *> positionals = app->get_options([](const Option *opt) { return opt->get_positional(); });
8753 
8754  // Print out positionals if any are left
8755  if(!positionals.empty()) {
8756  // Convert to help names
8757  std::vector<std::string> positional_names(positionals.size());
8758  std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [this](const Option *opt) {
8759  return make_option_usage(opt);
8760  });
8761 
8762  out << " " << detail::join(positional_names, " ");
8763  }
8764 
8765  // Add a marker if subcommands are expected or optional
8766  if(!app->get_subcommands(
8767  [](const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
8768  .empty()) {
8769  out << " " << (app->get_require_subcommand_min() == 0 ? "[" : "")
8770  << get_label(app->get_require_subcommand_max() < 2 || app->get_require_subcommand_min() > 1 ? "SUBCOMMAND"
8771  : "SUBCOMMANDS")
8772  << (app->get_require_subcommand_min() == 0 ? "]" : "");
8773  }
8774 
8775  out << std::endl;
8776 
8777  return out.str();
8778 }
8779 
8780 inline std::string Formatter::make_footer(const App *app) const {
8781  std::string footer = app->get_footer();
8782  if(footer.empty()) {
8783  return std::string{};
8784  }
8785  return footer + "\n";
8786 }
8787 
8788 inline std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
8789 
8790  // This immediately forwards to the make_expanded method. This is done this way so that subcommands can
8791  // have overridden formatters
8792  if(mode == AppFormatMode::Sub)
8793  return make_expanded(app);
8794 
8795  std::stringstream out;
8796  if((app->get_name().empty()) && (app->get_parent() != nullptr)) {
8797  if(app->get_group() != "Subcommands") {
8798  out << app->get_group() << ':';
8799  }
8800  }
8801 
8802  out << make_description(app);
8803  out << make_usage(app, name);
8804  out << make_positionals(app);
8805  out << make_groups(app, mode);
8806  out << make_subcommands(app, mode);
8807  out << '\n' << make_footer(app);
8808 
8809  return out.str();
8810 }
8811 
8812 inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mode) const {
8813  std::stringstream out;
8814 
8815  std::vector<const App *> subcommands = app->get_subcommands({});
8816 
8817  // Make a list in definition order of the groups seen
8818  std::vector<std::string> subcmd_groups_seen;
8819  for(const App *com : subcommands) {
8820  if(com->get_name().empty()) {
8821  if(!com->get_group().empty()) {
8822  out << make_expanded(com);
8823  }
8824  continue;
8825  }
8826  std::string group_key = com->get_group();
8827  if(!group_key.empty() &&
8828  std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
8829  return detail::to_lower(a) == detail::to_lower(group_key);
8830  }) == subcmd_groups_seen.end())
8831  subcmd_groups_seen.push_back(group_key);
8832  }
8833 
8834  // For each group, filter out and print subcommands
8835  for(const std::string &group : subcmd_groups_seen) {
8836  out << "\n" << group << ":\n";
8837  std::vector<const App *> subcommands_group = app->get_subcommands(
8838  [&group](const App *sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
8839  for(const App *new_com : subcommands_group) {
8840  if(new_com->get_name().empty())
8841  continue;
8842  if(mode != AppFormatMode::All) {
8843  out << make_subcommand(new_com);
8844  } else {
8845  out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
8846  out << "\n";
8847  }
8848  }
8849  }
8850 
8851  return out.str();
8852 }
8853 
8854 inline std::string Formatter::make_subcommand(const App *sub) const {
8855  std::stringstream out;
8856  detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
8857  return out.str();
8858 }
8859 
8860 inline std::string Formatter::make_expanded(const App *sub) const {
8861  std::stringstream out;
8862  out << sub->get_display_name(true) << "\n";
8863 
8864  out << make_description(sub);
8865  if(sub->get_name().empty() && !sub->get_aliases().empty()) {
8866  detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
8867  }
8868  out << make_positionals(sub);
8869  out << make_groups(sub, AppFormatMode::Sub);
8870  out << make_subcommands(sub, AppFormatMode::Sub);
8871 
8872  // Drop blank spaces
8873  std::string tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
8874  tmp = tmp.substr(0, tmp.size() - 1); // Remove the final '\n'
8875 
8876  // Indent all but the first line (the name)
8877  return detail::find_and_replace(tmp, "\n", "\n ") + "\n";
8878 }
8879 
8880 inline std::string Formatter::make_option_name(const Option *opt, bool is_positional) const {
8881  if(is_positional)
8882  return opt->get_name(true, false);
8883 
8884  return opt->get_name(false, true);
8885 }
8886 
8887 inline std::string Formatter::make_option_opts(const Option *opt) const {
8888  std::stringstream out;
8889 
8890  if(!opt->get_option_text().empty()) {
8891  out << " " << opt->get_option_text();
8892  } else {
8893  if(opt->get_type_size() != 0) {
8894  if(!opt->get_type_name().empty())
8895  out << " " << get_label(opt->get_type_name());
8896  if(!opt->get_default_str().empty())
8897  out << "=" << opt->get_default_str();
8898  if(opt->get_expected_max() == detail::expected_max_vector_size)
8899  out << " ...";
8900  else if(opt->get_expected_min() > 1)
8901  out << " x " << opt->get_expected();
8902 
8903  if(opt->get_required())
8904  out << " " << get_label("REQUIRED");
8905  }
8906  if(!opt->get_envname().empty())
8907  out << " (" << get_label("Env") << ":" << opt->get_envname() << ")";
8908  if(!opt->get_needs().empty()) {
8909  out << " " << get_label("Needs") << ":";
8910  for(const Option *op : opt->get_needs())
8911  out << " " << op->get_name();
8912  }
8913  if(!opt->get_excludes().empty()) {
8914  out << " " << get_label("Excludes") << ":";
8915  for(const Option *op : opt->get_excludes())
8916  out << " " << op->get_name();
8917  }
8918  }
8919  return out.str();
8920 }
8921 
8922 inline std::string Formatter::make_option_desc(const Option *opt) const { return opt->get_description(); }
8923 
8924 inline std::string Formatter::make_option_usage(const Option *opt) const {
8925  // Note that these are positionals usages
8926  std::stringstream out;
8927  out << make_option_name(opt, true);
8928  if(opt->get_expected_max() >= detail::expected_max_vector_size)
8929  out << "...";
8930  else if(opt->get_expected_max() > 1)
8931  out << "(" << opt->get_expected() << "x)";
8932 
8933  return opt->get_required() ? out.str() : "[" + out.str() + "]";
8934 }
8935 
8936 
8937 
8938 } // namespace CLI
App * clear_aliases()
clear all the aliases of the current App
Definition: CLI11.hpp:6900
void _move_option(Option *opt, App *app)
function that could be used by subclasses of App to shift options around into subcommands ...
Definition: CLI11.hpp:8066
void failure_message(std::function< std::string(const App *, const Error &e)> function)
Provide a function to print a help message. The function gets access to the App pointer and error...
Definition: CLI11.hpp:6449
virtual std::string make_option_desc(const Option *) const
This is the description. Default: Right column, on new line if left column too large.
Definition: CLI11.hpp:8922
bool empty() const
True if the option was not passed.
Definition: CLI11.hpp:4215
bool get_allow_extras() const
Get the status of allow extras.
Definition: CLI11.hpp:6841
Option * check(std::function< std::string(const std::string &)> Validator, std::string Validator_description="", std::string Validator_name="")
Adds a Validator. Takes a const string& and returns an error message (empty if conversion/check is ok...
Definition: CLI11.hpp:4299
std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
Definition: CLI11.hpp:6829
virtual std::string make_option(const Option *opt, bool is_positional) const
This prints out an option help line, either positional or optional form.
Definition: CLI11.hpp:3860
Range(T min, T max, const std::string &validator_name=std::string{})
This produces a range with min and max inclusive.
Definition: CLI11.hpp:3045
void run_callback(bool final_mode=false, bool suppress_final_callback=false)
Internal function to run (App) callback, bottom up.
Definition: CLI11.hpp:7084
virtual ~FormatterBase() noexcept
Adding a destructor in this form to work around bug in GCC 4.7.
Definition: CLI11.hpp:3760
App * get_option_group(std::string group_name) const
Check to see if an option group is part of this App.
Definition: CLI11.hpp:6226
Multiply a number by a factor using given mapping.
Definition: CLI11.hpp:3474
Thrown when an option already exists.
Definition: CLI11.hpp:649
char get_delimiter() const
Get the current delimiter char.
Definition: CLI11.hpp:3992
const std::string & get_single_name() const
Get a single name for the option, first of lname, pname, sname, envname.
Definition: CLI11.hpp:4552
std::size_t get_require_option_min() const
Get the required min option value.
Definition: CLI11.hpp:6832
This class is simply to allow tests access to App&#39;s protected functions.
Definition: CLI11.hpp:8292
bool get_callback_run() const
See if the callback has been run already.
Definition: CLI11.hpp:4901
This class provides a converter for configuration files.
Definition: CLI11.hpp:2538
bool get_prefix_command() const
Get the prefix command status.
Definition: CLI11.hpp:6838
bool get_silent() const
Get the status of silence.
Definition: CLI11.hpp:6850
Option * each(const std::function< void(std::string)> &func)
Adds a user supplied function to run on each item passed in (communicate though lambda capture) ...
Definition: CLI11.hpp:4332
std::size_t get_require_option_max() const
Get the required max option value.
Definition: CLI11.hpp:6835
std::size_t _count_remaining_positionals(bool required_only=false) const
Count the required remaining positional arguments.
Definition: CLI11.hpp:7632
bool disabled_
If set to true the subcommand is disabled and cannot be used, ignored for main app.
Definition: CLI11.hpp:5246
std::string name_
The name for search purposes of the Validator.
Definition: CLI11.hpp:2661
App * prefix_command(bool allow=true)
Do not parse anything after the first unrecognized option and return.
Definition: CLI11.hpp:5629
std::string get_footer() const
Generate and return the footer.
Definition: CLI11.hpp:6823
int get_expected_min() const
The number of times the option expects to be included.
Definition: CLI11.hpp:4568
static auto parse_subcommand(App *app, Args &&... args) -> typename std::result_of< decltype(&App::_parse_subcommand)(App, Args...)>::type
Wrap _parse_subcommand, perfectly forward arguments and return.
Definition: CLI11.hpp:8314
Definition: sfinae_test.cpp:28
Options
Adjust AsNumberWithUnit behavior.
Definition: CLI11.hpp:3480
Transformer(T mapping, F filter_function)
This checks to see if an item is in a set: pointer or copy version.
Definition: CLI11.hpp:3331
bool _parse_subcommand(std::vector< std::string > &args)
Parse a subcommand, modify args and continue.
Definition: CLI11.hpp:7782
App * config_formatter(std::shared_ptr< Config > fmt)
Set the config formatter.
Definition: CLI11.hpp:5696
Option * excludes(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition: CLI11.hpp:4423
Validate the input as a particular type.
Definition: CLI11.hpp:3020
CRTP * required(bool value=true)
Set the option as required.
Definition: CLI11.hpp:3958
~FormatterLambda() noexcept override
Adding a destructor (mostly to make GCC 4.7 happy)
Definition: CLI11.hpp:3805
std::size_t count() const
Count the total number of times an option was passed.
Definition: CLI11.hpp:4212
const Option * operator[](const char *option_name) const
Shortcut bracket operator for getting a pointer to an option.
Definition: CLI11.hpp:6799
bool has_automatic_name_
If set to true the name was automatically generated from the command line vs a user set name...
Definition: CLI11.hpp:5240
const App * get_parent() const
Get the parent of this subcommand (or nullptr if master app) (const version)
Definition: CLI11.hpp:6891
std::shared_ptr< ConfigBase > get_config_formatter_base() const
Access the config formatter as a configBase pointer.
Definition: CLI11.hpp:6688
Option * add_flag(std::string flag_name, T &flag_count, std::string flag_description="")
Add option for flag with integer result - defaults to allowing multiple passings, but can be forced t...
Definition: CLI11.hpp:5963
virtual std::string to_flag(const ConfigItem &item) const
Get a flag value.
Definition: CLI11.hpp:2550
virtual std::string make_subcommands(const App *app, AppFormatMode mode) const
This prints out all the subcommands.
Definition: CLI11.hpp:8812
Option * needs(std::string opt_name)
Can find a string if needed.
Definition: CLI11.hpp:4372
App * require_option()
The argumentless form of require option requires 1 or more options be used.
Definition: CLI11.hpp:6292
App * require_option(std::size_t min, std::size_t max)
Explicitly control the number of options required.
Definition: CLI11.hpp:6314
const std::string & get_name() const
Get the name of the Validator.
Definition: CLI11.hpp:2734
virtual std::string make_option_name(const Option *, bool) const
This is the name part of an option, Default: left column.
Definition: CLI11.hpp:8880
const Option * get_version_ptr() const
Get a pointer to the version option. (const)
Definition: CLI11.hpp:6885
option_state
enumeration for the option state machine
Definition: CLI11.hpp:4180
const std::string & get_description() const
Get the description.
Definition: CLI11.hpp:4593
std::shared_ptr< Config > get_config_formatter() const
Access the config formatter.
Definition: CLI11.hpp:6685
void parse(std::vector< std::string > &args)
The real work is done here.
Definition: CLI11.hpp:6409
CRTP * group(const std::string &name)
Changes the group membership.
Definition: CLI11.hpp:3952
Definition: CLI11.hpp:139
This is just a safety check to verify selection and parsing match - you should not ever see it String...
Definition: CLI11.hpp:846
Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
You can pass in as many filter functions as you like, they nest.
Definition: CLI11.hpp:3367
void clear()
Reset the parsed data.
Definition: CLI11.hpp:6345
Anything that can error in Parse.
Definition: CLI11.hpp:664
std::vector< std::string > remaining(bool recurse=false) const
This returns the missing options from the current subcommand.
Definition: CLI11.hpp:6969
int get_type_size() const
The number of arguments the option expects.
Definition: CLI11.hpp:4518
Option * set_version_flag(std::string flag_name="", const std::string &versionString="", const std::string &version_help="Display program version information and exit")
Set a version flag and version display string, replace the existing one if present.
Definition: CLI11.hpp:5880
Option * add_option(std::string option_name, T &option_description)
Add option with description but with no variable assignment or callback.
Definition: CLI11.hpp:5841
bool get_required() const
True if this is a required option.
Definition: CLI11.hpp:3977
std::vector< std::string > aliases_
Alias names for the subcommand.
Definition: CLI11.hpp:5395
virtual std::string make_subcommand(const App *sub) const
This prints out a subcommand.
Definition: CLI11.hpp:8854
int get_application_index() const
Get the current value of the application index.
Definition: CLI11.hpp:2764
Thrown when too many positionals or options are found.
Definition: CLI11.hpp:811
std::string get_description() const
Get the app or subcommand description.
Definition: CLI11.hpp:6698
App * parent_
A pointer to the parent if this is a subcommand.
Definition: CLI11.hpp:5389
App * silent(bool silence=true)
silence the subcommand from showing up in the processed list
Definition: CLI11.hpp:5565
bool remove_excludes(Option *opt)
Removes an option from the excludes list of this subcommand.
Definition: CLI11.hpp:6583
std::vector< App_p > subcommands_
Storage for subcommand list.
Definition: CLI11.hpp:5336
int get_expected_max() const
The max number of times the option expects to be included.
Definition: CLI11.hpp:4570
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition: CLI11.hpp:940
Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code...
Definition: CLI11.hpp:697
std::string config_to_str(bool default_also=false, bool write_description=false) const
Produce a string that could be read in as a config of the current values of the App.
Definition: CLI11.hpp:6640
Combination of the element type and value type - remove pointer (including smart pointers) and get th...
Definition: CLI11.hpp:937
App * allow_extras(bool allow=true)
Remove the error when extras are left over on the command line.
Definition: CLI11.hpp:5547
App(std::string app_description="", std::string app_name="")
Create a new program. Pass in the same arguments as main(), along with a help string.
Definition: CLI11.hpp:5448
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&... args)
This allows in-place construction.
Definition: CLI11.hpp:3381
bool check_name(const std::string &name) const
Check a name. Requires "-" or "--" for short / long, supports positional name.
Definition: CLI11.hpp:4725
Option * get_config_ptr()
Get a pointer to the config option.
Definition: CLI11.hpp:6876
bool check_sname(std::string name) const
Requires "-" to be removed from string.
Definition: CLI11.hpp:4755
std::vector< Option_p > options_
The list of options, stored locally.
Definition: CLI11.hpp:5272
void _parse(std::vector< std::string > &&args)
Internal parse function.
Definition: CLI11.hpp:7491
bool check_lname(std::string name) const
Requires "--" to be removed from string.
Definition: CLI11.hpp:4760
std::string envname_
If given, check the environment for this option.
Definition: CLI11.hpp:4114
std::vector< std::string > parents
This is the list of parents.
Definition: CLI11.hpp:2521
Check for complex.
Definition: CLI11.hpp:1037
ConfigBase * comment(char cchar)
Specify the configuration for comment characters.
Definition: CLI11.hpp:2594
Check for an existing directory (returns error message if check fails)
Definition: CLI11.hpp:2932
virtual std::string make_description(const App *app) const
This displays the description line.
Definition: CLI11.hpp:8712
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition: CLI11.hpp:2672
bool get_ignore_case() const
The status of ignore case.
Definition: CLI11.hpp:3980
Option * add_option_no_stream(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
Definition: CLI11.hpp:5794
Option * add_option(std::string option_name)
Add option with no description or variable assignment.
Definition: CLI11.hpp:5833
CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
You can pass in as many filter functions as you like, they nest.
Definition: CLI11.hpp:3443
bool _parse_single_config(const ConfigItem &item, std::size_t level=0)
Fill in a single config option.
Definition: CLI11.hpp:7519
Produce a bounded range (factory). Min and max are inclusive.
Definition: CLI11.hpp:3076
bool get_ignore_case() const
Check the status of ignore_case.
Definition: CLI11.hpp:6802
Validator * get_validator(const std::string &Validator_name="")
Get a named Validator.
Definition: CLI11.hpp:4342
Range(T max, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition: CLI11.hpp:3065
Class wrapping some of the accessors of Validator.
Definition: CLI11.hpp:2861
App * preparse_callback(std::function< void(std::size_t)> pp_callback)
Set a callback to execute prior to parsing.
Definition: CLI11.hpp:5490
int get_expected() const
The number of times the option expects to be included.
Definition: CLI11.hpp:4565
std::string get_envname() const
The environment variable associated to this value.
Definition: CLI11.hpp:4529
bool get_disable_flag_override() const
The status of configurable.
Definition: CLI11.hpp:3989
OptionDefaults * ignore_case(bool value=true)
Ignore the case of the option name.
Definition: CLI11.hpp:4066
void _trigger_pre_parse(std::size_t remaining_args)
Trigger the pre_parse callback if needed.
Definition: CLI11.hpp:7967
int get_items_expected_min() const
The total min number of expected string values to be used.
Definition: CLI11.hpp:4573
A copy of std::void_t from C++17 (helper for C++11 and C++14)
Definition: CLI11.hpp:887
bool parsed() const
Check to see if this subcommand was parsed, true only if received on command line.
Definition: CLI11.hpp:5702
Option * needs(Option *opt)
Sets required options.
Definition: CLI11.hpp:4364
std::set< Option * > excludes_
A list of options that are excluded with this option.
Definition: CLI11.hpp:4159
translate named items to other or a value set
Definition: CLI11.hpp:3375
bool remove_needs(Option *opt)
Removes an option from the needs list of this subcommand.
Definition: CLI11.hpp:6605
Validator name(std::string validator_name) const
Specify the type string.
Definition: CLI11.hpp:2728
const std::vector< Option * > & parse_order() const
This gets a vector of pointers with the original parse order.
Definition: CLI11.hpp:6966
Definition: CLI11.hpp:4090
void _process_extras()
Throw an error if anything is left over and should not be.
Definition: CLI11.hpp:7422
void _process_callbacks()
Process callbacks. Runs on all subcommands.
Definition: CLI11.hpp:7217
Option * type_name_fn(std::function< std::string()> typefun)
Set the type function to run when displayed on this option.
Definition: CLI11.hpp:4908
Validator operator|(const Validator &other) const
Combining validators is a new validator.
Definition: CLI11.hpp:2798
std::vector< App * > get_subcommands() const
Get a subcommand pointer list to the currently selected subcommands (after parsing by default...
Definition: CLI11.hpp:6492
Definition: pointer_wrapper.hpp:23
bool nonpositional() const
True if option has at least one non-positional name.
Definition: CLI11.hpp:4587
ConfigINI generates a "standard" INI compliant output.
Definition: CLI11.hpp:2626
bool _parse_arg(std::vector< std::string > &args, detail::Classifier current_type)
Parse a short (false) or long (true) argument, must be at the top of the list return true if the argu...
Definition: CLI11.hpp:7812
App * ignore_case(bool value=true)
Ignore case. Subcommands inherit value.
Definition: CLI11.hpp:5635
static auto first(Q &&pair_value) -> decltype(std::get< 0 >(std::forward< Q >(pair_value)))
Get the first value (really just the underlying value)
Definition: CLI11.hpp:967
bool _parse_positional(std::vector< std::string > &args, bool haltOnSubcommand)
Parse a positional, go up the tree to check.
Definition: CLI11.hpp:7659
void _move_to_missing(detail::Classifier val_type, const std::string &val)
Helper function to place extra values in the most appropriate position.
Definition: CLI11.hpp:8048
bool get_validate_positionals() const
Get the status of validating positionals.
Definition: CLI11.hpp:6861
Definition: sfinae_test.cpp:18
Check to see if something is bool (fail check by default)
Definition: CLI11.hpp:896
Extension of App to better manage groups of options.
Definition: CLI11.hpp:8107
Validator application_index(int app_index) const
Specify the application index of a validator.
Definition: CLI11.hpp:2758
void _process_env()
Get envname options if not yet passed. Runs on all subcommands.
Definition: CLI11.hpp:7184
CRTP * join(char delim)
Set the multi option policy to join with a specific delimiter.
Definition: CLI11.hpp:4031
App * formatter(std::shared_ptr< FormatterBase > fmt)
Set the help formatter.
Definition: CLI11.hpp:5684
Option * set_version_flag(std::string flag_name, std::function< std::string()> vfunc, const std::string &version_help="Display program version information and exit")
Generate the version string through a callback function.
Definition: CLI11.hpp:5899
Check for an non-existing path.
Definition: CLI11.hpp:2963
virtual std::string make_option_opts(const Option *) const
This is the options part of the name, Default: combined into left column.
Definition: CLI11.hpp:8887
App(std::string app_description, std::string app_name, App *parent)
Special private constructor for subcommand.
Definition: CLI11.hpp:5410
AsSizeValue(bool kb_is_1000)
If kb_is_1000 is true, interpret &#39;kb&#39;, &#39;k&#39; as 1000 and &#39;kib&#39;, &#39;ki&#39; as 1024 (same applies to higher or...
Definition: CLI11.hpp:3623
RangeType< double > Range
3.0.0 TODO: break reverse-compatibility by changing RangeType to Range.
Definition: range.hpp:19
std::function< std::string(std::string &)> func_
This is the base function that is to be called.
Definition: CLI11.hpp:2659
Option * add_flag_callback(std::string flag_name, std::function< void(void)> function, std::string flag_description="")
Add option for callback that is triggered with a true flag and takes no arguments.
Definition: CLI11.hpp:6017
Option * envname(std::string name)
Sets environment variable to read if no option given.
Definition: CLI11.hpp:4440
bool _parse_single(std::vector< std::string > &args, bool &positional_only)
Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if mis...
Definition: CLI11.hpp:7589
void column_width(std::size_t val)
Set the column width.
Definition: CLI11.hpp:3773
callback_t get_callback() const
Get the callback function.
Definition: CLI11.hpp:4541
Option * disable_flag_override(bool value=true)
Disable flag overrides values, e.g. –flag=is not allowed.
Definition: CLI11.hpp:4509
std::string name
This is the name.
Definition: CLI11.hpp:2524
Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
Making an option by hand is not defined, it must be made by the App class.
Definition: CLI11.hpp:4199
const Option * operator[](const std::string &option_name) const
Shortcut bracket operator for getting a pointer to an option.
Definition: CLI11.hpp:6796
App * callback(std::function< void()> app_callback)
Set a callback for execution when all parsing and processing has completed.
Definition: CLI11.hpp:5465
bool get_positionals_at_end() const
Check the status of the allow windows style options.
Definition: CLI11.hpp:6814
ConfigBase * arrayDelimiter(char aSep)
Specify the delimiter character for an array.
Definition: CLI11.hpp:2605
T * add_option_group(std::string group_name, std::string group_description="")
creates an option group as part of the given app
Definition: CLI11.hpp:6107
Validate the given string is a legal ipv4 address.
Definition: CLI11.hpp:2977
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value)
Definition: CLI11.hpp:950
Transformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&... args)
This allows in-place construction.
Definition: CLI11.hpp:3323
Option * add_flag(std::string flag_name)
Add a flag with no description or variable assignment.
Definition: CLI11.hpp:5946
std::string make_groups(const App *app, AppFormatMode mode) const
This prints out all the groups of options.
Definition: CLI11.hpp:8688
OptionDefaults * delimiter(char value='\0')
set a delimiter character to split up single arguments to treat as multiple inputs ...
Definition: CLI11.hpp:4084
bool remove_subcommand(App *subcom)
Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed...
Definition: CLI11.hpp:6154
Option * excludes(Option *opt)
Sets excluded options.
Definition: CLI11.hpp:4398
Converts a human-readable size string (with unit literal) to uin64_t size.
Definition: CLI11.hpp:3612
std::vector< const App * > get_subcommands(const std::function< bool(const App *)> &filter) const
Get a filtered subcommand pointer list from the original definition list.
Definition: CLI11.hpp:6496
template to get the underlying value type if it exists or use a default
Definition: CLI11.hpp:1195
App * get_parent()
Get the parent of this subcommand (or nullptr if master app)
Definition: CLI11.hpp:6888
Option * default_function(const std::function< std::string()> &func)
Set a capture function for the default. Mostly used by App.
Definition: CLI11.hpp:4967
std::vector< std::string > fnames_
a list of flag names with specified default values;
Definition: CLI11.hpp:4108
bool remove_excludes(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list...
Definition: CLI11.hpp:4429
Option * add_flag(std::string flag_name, T &flag_description)
Add flag with description but with no variable assignment or callback takes a constant string...
Definition: CLI11.hpp:5954
std::vector< std::string > snames_
A list of the short names (-a) without the leading dashes.
Definition: CLI11.hpp:4098
Option * excludes(std::string opt_name)
Can find a string if needed.
Definition: CLI11.hpp:4414
Transformer(T &&mapping)
direct map of std::string to std::string
Definition: CLI11.hpp:3327
const Option * get_help_ptr() const
Get a pointer to the help flag. (const)
Definition: CLI11.hpp:6870
Option * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times (or another policy)
Definition: CLI11.hpp:4495
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
Definition: CLI11.hpp:2663
Thrown when a required option is missing.
Definition: CLI11.hpp:733
Definition: CLI11.hpp:3153
Option * get_option(std::string option_name)
Get an option by name (non-const version)
Definition: CLI11.hpp:6787
std::string help(std::string prev="", AppFormatMode mode=AppFormatMode::Normal) const
Makes a help message, using the currently configured formatter Will only do one subcommand at a time...
Definition: CLI11.hpp:6646
std::string get_label(std::string key) const
Get the current value of a name (REQUIRED, etc.)
Definition: CLI11.hpp:3780
Validator * get_validator(int index)
Get a Validator by index NOTE: this may not be the order of definition.
Definition: CLI11.hpp:4355
IsMember(T set, F filter_function)
This checks to see if an item is in a set: pointer or copy version.
Definition: CLI11.hpp:3262
void copy_to(T *other) const
Copy the contents to another similar class (one based on OptionBase)
Definition: CLI11.hpp:3936
This is the CRTP base class for Option and OptionDefaults.
Definition: CLI11.hpp:3904
This can be specialized to override the type deduction for IsMember.
Definition: CLI11.hpp:916
FormatterLambda(funct_t funct)
Create a FormatterLambda with a lambda function.
Definition: CLI11.hpp:3802
bool get_fallthrough() const
Check the status of fallthrough.
Definition: CLI11.hpp:6808
std::vector< Option * > get_options(const std::function< bool(Option *)> filter={})
Non-const version of the above.
Definition: CLI11.hpp:6724
CRTP * take_first()
Set the multi option policy to take last.
Definition: CLI11.hpp:4010
bool get_configurable() const
The status of configurable.
Definition: CLI11.hpp:3986
Option * transform(Validator Validator, const std::string &Validator_name="")
Adds a transforming Validator with a built in type name.
Definition: CLI11.hpp:4308
std::size_t count_all() const
Get a count of all the arguments processed in options and subcommands, this excludes arguments which ...
Definition: CLI11.hpp:6242
App * enabled_by_default(bool enable=true)
Set the subcommand to be enabled by default, so on clear(), at the start of each parse it is enabled ...
Definition: CLI11.hpp:5582
App * disabled(bool disable=true)
Disable the subcommand or option group.
Definition: CLI11.hpp:5559
bool operator==(const Option &other) const
If options share any of the same names, they are equal (not counting positional)
Definition: CLI11.hpp:4722
CLI::App_p get_subcommand_ptr(App *subcom) const
Check to see if a subcommand is part of this command and get a shared_ptr to it.
Definition: CLI11.hpp:6198
Option * add_flag_function(std::string flag_name, std::function< void(std::int64_t)> function, std::string flag_description="")
Add option for callback with an integer value.
Definition: CLI11.hpp:6033
std::vector< ConfigItem > from_file(const std::string &name)
Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure...
Definition: CLI11.hpp:2558
results_t reduced_results() const
Get a copy of the results.
Definition: CLI11.hpp:4844
OptionDefaults * option_defaults()
Get the OptionDefault object, to set option defaults.
Definition: CLI11.hpp:5705
Thrown when parsing an INI file and it is missing.
Definition: CLI11.hpp:703
App * allow_config_extras(config_extras_mode mode)
ignore extras in config files
Definition: CLI11.hpp:5623
void _process_extras(std::vector< std::string > &args)
Throw an error if anything is left over and should not be.
Definition: CLI11.hpp:7438
Option * get_version_ptr()
Get a pointer to the version option.
Definition: CLI11.hpp:6882
static auto parse_arg(App *app, Args &&... args) -> typename std::result_of< decltype(&App::_parse_arg)(App, Args...)>::type
Wrap _parse_short, perfectly forward arguments and return.
Definition: CLI11.hpp:8307
OptionDefaults * ignore_underscore(bool value=true)
Ignore underscores in the option name.
Definition: CLI11.hpp:4072
bool _has_remaining_positionals() const
Count the required remaining positional arguments.
Definition: CLI11.hpp:7646
std::ostream & operator<<(std::ostream &in, const T &item)
output streaming for enumerations
Definition: CLI11.hpp:148
void _parse(std::vector< std::string > &args)
Internal parse function.
Definition: CLI11.hpp:7462
Definition: CLI11.hpp:1015
bool get_disabled() const
Get the status of disabled.
Definition: CLI11.hpp:6847
Option * check(Validator validator, const std::string &validator_name="")
Adds a Validator with a built in type name.
Definition: CLI11.hpp:4290
void inject_separator(bool value=true)
Set the value of the separator injection flag.
Definition: CLI11.hpp:4964
App * configurable(bool value=true)
Specify that the subcommand can be triggered by a config file.
Definition: CLI11.hpp:5663
bool fallthrough_
Allow subcommand fallthrough, so that parent commands can collect commands after subcommand. INHERITABLE.
Definition: CLI11.hpp:5345
App * description(std::string app_description)
Set the description of the app.
Definition: CLI11.hpp:6701
This will only trigger for actual void type.
Definition: CLI11.hpp:1203
Option * add_option(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
Definition: CLI11.hpp:5770
std::string get_name(bool positional=false, bool all_options=false) const
Gets a comma separated list of names.
Definition: CLI11.hpp:4616
Produce a range (factory). Min and max are inclusive.
Definition: CLI11.hpp:3038
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition: CLI11.hpp:710
Check for an existing path.
Definition: CLI11.hpp:2949
Validator description(std::string validator_desc) const
Specify the type string.
Definition: CLI11.hpp:2710
OptionDefaults * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times.
Definition: CLI11.hpp:4060
ConfigBase * quoteCharacter(char qString, char qChar)
Specify the quote characters used around strings and characters.
Definition: CLI11.hpp:2615
Option * run_callback_for_default(bool value=true)
Set the value of run_callback_for_default which controls whether the callback function should be call...
Definition: CLI11.hpp:4282
Usually something like –help-all on command line.
Definition: CLI11.hpp:683
App * require_subcommand()
The argumentless form of require subcommand requires 1 or more subcommands.
Definition: CLI11.hpp:6263
forward declare the subtype_count_min structure
Definition: CLI11.hpp:1230
App * add_subcommand(App *subcom)
Add an existing subcommand to be a member of an option_group.
Definition: CLI11.hpp:8132
void clear()
Clear the parsed results (mostly for testing)
Definition: CLI11.hpp:4221
std::string get_description() const
Generate type description information for the Validator.
Definition: CLI11.hpp:2716
std::vector< std::string > inputs
Listing of inputs.
Definition: CLI11.hpp:2527
Option * add_result(std::vector< std::string > s)
Puts a result at the end.
Definition: CLI11.hpp:4832
void label(std::string key, std::string val)
Set the "REQUIRED" label.
Definition: CLI11.hpp:3770
CLI::App_p get_subcommand_ptr(int index=0) const
Get an owning pointer to subcommand by index.
Definition: CLI11.hpp:6216
Thrown when a requires option is missing.
Definition: CLI11.hpp:797
std::size_t remaining_size(bool recurse=false) const
This returns the number of remaining options, minus the – separator.
Definition: CLI11.hpp:7003
int get_inject_separator() const
The number of arguments the option expects.
Definition: CLI11.hpp:4526
Construction errors (not in parsing)
Definition: CLI11.hpp:602
std::string version() const
Displays a version string.
Definition: CLI11.hpp:6661
std::set< Option * > needs_
A list of options that are required with this option.
Definition: CLI11.hpp:4156
All errors derive from this one.
Definition: CLI11.hpp:584
This is the minimum requirements to run a formatter.
Definition: CLI11.hpp:3738
const std::string & _compare_subcommand_names(const App &subcom, const App &base) const
Helper function to run through all possible comparisons of subcommand names to check there is no over...
Definition: CLI11.hpp:7998
bool prefix_command_
If true, return immediately on an unrecognized option (implies allow_extras) INHERITABLE.
Definition: CLI11.hpp:5237
App * allow_windows_style_options(bool value=true)
Allow windows style options, such as /opt.
Definition: CLI11.hpp:5651
void _process_config_file()
Read and process a configuration file (main app only)
Definition: CLI11.hpp:7151
Thrown when validation of results fails.
Definition: CLI11.hpp:726
void _configure()
configure subcommands to enable parsing through the current object set the correct fallthrough and pr...
Definition: CLI11.hpp:7063
Thrown when the wrong number of arguments has been received.
Definition: CLI11.hpp:770
bool required_
True if this is a required option.
Definition: CLI11.hpp:3912
void add_options(Option *opt)
Add an existing option to the Option_group.
Definition: CLI11.hpp:8124
Option * transform(const std::function< std::string(std::string)> &func, std::string transform_description="", std::string transform_name="")
Adds a Validator-like function that can change result.
Definition: CLI11.hpp:4316
std::vector< std::pair< std::string, std::string > > default_flag_values_
A list of the flag names with the appropriate default value, the first part of the pair should be dup...
Definition: CLI11.hpp:4105
App * add_subcommand(CLI::App_p subcom)
Add a previously created app as a subcommand.
Definition: CLI11.hpp:6140
Bound(T max)
Range of one value is 0 to value.
Definition: CLI11.hpp:3103
std::vector< const Option * > get_options(const std::function< bool(const Option *)> filter={}) const
Get the list of options (user facing function, so returns raw pointers), has optional filter function...
Definition: CLI11.hpp:6707
App * required(bool require=true)
Remove the error when extras are left over on the command line.
Definition: CLI11.hpp:5553
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition: CLI11.hpp:2674
virtual std::string make_group(std::string group, bool is_positional, std::vector< const Option *> opts) const
This prints out a group of options with title.
Definition: CLI11.hpp:8667
Validator & name(std::string validator_name)
Specify the type string.
Definition: CLI11.hpp:2723
std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override
Convert an app into a configuration.
Definition: CLI11.hpp:8574
Option * allow_extra_args(bool value=true)
Set the value of allow_extra_args which allows extra value arguments on the flag or option to be incl...
Definition: CLI11.hpp:4273
Option * description(std::string option_description)
Set the description.
Definition: CLI11.hpp:4596
std::string name_
Subcommand name or program name (from parser if name is empty)
Definition: CLI11.hpp:5224
This is a version of OptionBase that only supports setting values, for defaults.
Definition: CLI11.hpp:4053
CRTP * join()
Set the multi option policy to join.
Definition: CLI11.hpp:4024
Set of overloads to get the type size of an object.
Definition: CLI11.hpp:1227
ConfigBase * arrayBounds(char aStart, char aEnd)
Specify the start and end characters for an array.
Definition: CLI11.hpp:2599
Translate named items to other or a value set.
Definition: CLI11.hpp:3317
const Option * get_option_no_throw(std::string option_name) const noexcept
Get an option by name (noexcept const version)
Definition: CLI11.hpp:6759
App * alias(std::string app_name)
Set an alias for the app.
Definition: CLI11.hpp:5514
App * formatter_fn(std::function< std::string(const App *, std::string, AppFormatMode)> fmt)
Set the help formatter.
Definition: CLI11.hpp:5690
std::string operator()(std::string &str) const
This is the required operator for a Validator - provided to help users (CLI11 uses the member func di...
Definition: CLI11.hpp:2684
bool remove_needs(App *app)
Removes a subcommand from the needs list of this subcommand.
Definition: CLI11.hpp:6615
const Option * get_option(std::string option_name) const
Get an option by name.
Definition: CLI11.hpp:6778
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition: CLI11.hpp:3258
Definition: CLI11.hpp:1062
detail::Classifier _recognize(const std::string &current, bool ignore_used_subcommands=true) const
Selects a Classifier enum based on the type of the current argument.
Definition: CLI11.hpp:7124
ConfigBase * valueSeparator(char vSep)
Specify the delimiter between a name and value.
Definition: CLI11.hpp:2610
int get_type_size_min() const
The minimum number of arguments the option expects.
Definition: CLI11.hpp:4521
int get_type_size_max() const
The maximum number of arguments the option expects.
Definition: CLI11.hpp:4523
virtual std::string make_usage(const App *app, std::string name) const
This displays the usage line.
Definition: CLI11.hpp:8738
bool remove_excludes(App *app)
Removes a subcommand from the excludes list of this subcommand.
Definition: CLI11.hpp:6593
Option * get_help_ptr()
Get a pointer to the help flag.
Definition: CLI11.hpp:6867
Option * expected(int value_min, int value_max)
Set the range of expected arguments.
Definition: CLI11.hpp:4253
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition: CLI11.hpp:2753
Option * set_config(std::string option_name="", std::string default_filename="", const std::string &help_message="Read an ini file", bool config_required=false)
Set a configuration ini file option, or clear it if no name passed.
Definition: CLI11.hpp:6057
Option * type_size(int option_type_size)
Set a custom option size.
Definition: CLI11.hpp:4920
App * immediate_callback(bool immediate=true)
Set the subcommand callback to be executed immediately on subcommand completion.
Definition: CLI11.hpp:5593
CRTP * take_last()
Set the multi option policy to take last.
Definition: CLI11.hpp:4003
int exit(const Error &e, std::ostream &out=std::cout, std::ostream &err=std::cerr) const
Print a nice error message and return the exit code.
Definition: CLI11.hpp:6454
This is a specialty override for lambda functions.
Definition: CLI11.hpp:3794
std::size_t count() const
No argument version of count counts the number of times this subcommand was passed in...
Definition: CLI11.hpp:6238
config_extras_mode get_allow_config_extras() const
Get the status of allow extras.
Definition: CLI11.hpp:6864
App * footer(std::string footer_string)
Set footer.
Definition: CLI11.hpp:6629
App * allow_config_extras(bool allow=true)
ignore extras in config files
Definition: CLI11.hpp:5612
const std::string & get_name() const
Get the name of the current app.
Definition: CLI11.hpp:6894
App * require_subcommand(int value)
Require a subcommand to be given (does not affect help call) The number required can be given...
Definition: CLI11.hpp:6272
Handy helper to access the element_type generically.
Definition: CLI11.hpp:929
CRTP * delimiter(char value='\0')
Allow in a configuration file.
Definition: CLI11.hpp:4045
void parse(int argc, const char *const *argv)
Parses the command line - throws errors.
Definition: CLI11.hpp:6362
static auto second(Q &&pair_value) -> decltype(std::get< 1 >(std::forward< Q >(pair_value)))
Get the second value (really just the underlying value)
Definition: CLI11.hpp:971
std::string fullname() const
The list of parents and name joined by ".".
Definition: CLI11.hpp:2530
void increment_parsed()
Internal function to recursively increment the parsed counter on the current app as well unnamed subc...
Definition: CLI11.hpp:7454
OptionDefaults * disable_flag_override(bool value=true)
Disable overriding flag values with an &#39;=&#39; segment.
Definition: CLI11.hpp:4078
Verify items are in a set.
Definition: CLI11.hpp:3248
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
Definition: CLI11.hpp:946
void results(T &output) const
Get the results as a specified type.
Definition: CLI11.hpp:4863
This is a successful completion on parsing, supposed to exit.
Definition: CLI11.hpp:671
App * final_callback(std::function< void()> app_callback)
Set a callback for execution when all parsing and processing has completed aliased as callback...
Definition: CLI11.hpp:5476
std::vector< std::string > remaining_for_passthrough(bool recurse=false) const
This returns the missing options in a form ready for processing by another command line program...
Definition: CLI11.hpp:6996
Definition: CLI11.hpp:1092
This will only trigger for actual void type.
Definition: CLI11.hpp:1233
CRTP * configurable(bool value=true)
Allow in a configuration file.
Definition: CLI11.hpp:4039
IsMember(std::initializer_list< T > values, Args &&... args)
This allows in-place construction using an initializer list.
Definition: CLI11.hpp:3254
std::vector< std::string > lnames_
A list of the long names (--long) without the leading dashes.
Definition: CLI11.hpp:4101
App * name(std::string app_name="")
Set a name for the app (empty will use parser to set the name)
Definition: CLI11.hpp:5496
App * get_subcommand(int index=0) const
Get a pointer to subcommand by index.
Definition: CLI11.hpp:6188
Check to see if something is a shared pointer.
Definition: CLI11.hpp:902
bool get_run_callback_for_default() const
Get the current value of run_callback_for_default.
Definition: CLI11.hpp:4287
Some validators that are provided.
Definition: CLI11.hpp:2652
bool get_immediate_callback() const
Get the status of disabled.
Definition: CLI11.hpp:6853
App * add_subcommand(std::string subcommand_name="", std::string subcommand_description="")
Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag.
Definition: CLI11.hpp:6121
bool has_description() const
True if option has description.
Definition: CLI11.hpp:4590
IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
You can pass in as many filter functions as you like, they nest (string only currently) ...
Definition: CLI11.hpp:3306
App * get_subcommand(std::string subcom) const
Check to see if a subcommand is part of this command (text version)
Definition: CLI11.hpp:6181
CLI::App_p get_subcommand_ptr(std::string subcom) const
Check to see if a subcommand is part of this command (text version)
Definition: CLI11.hpp:6208
std::vector< ConfigItem > from_config(std::istream &input) const override
Convert a configuration into an app.
Definition: CLI11.hpp:8474
Thrown when an option is set to conflicting values (non-vector and multi args, for example) ...
Definition: CLI11.hpp:607
const std::string & get_group() const
Get the group of this option.
Definition: CLI11.hpp:3974
Option * add_option(std::string option_name, callback_t option_callback, std::string option_description="", bool defaulted=false, std::function< std::string()> func={})
Add an option, will automatically understand the type for common types.
Definition: CLI11.hpp:5725
bool get_modifying() const
Get a boolean if the validator is allowed to modify the input returns true if it can modify the input...
Definition: CLI11.hpp:2769
Option * add_option_function(std::string option_name, const std::function< void(const ArgType &)> &func, std::string option_description="")
Add option for a callback of a specific type.
Definition: CLI11.hpp:5812
bool got_subcommand(const App *subcom) const
Check to see if given subcommand was selected.
Definition: CLI11.hpp:6530
const std::string & matching_name(const Option &other) const
If options share any of the same names, find it.
Definition: CLI11.hpp:4701
bool check_fname(std::string name) const
Requires "--" to be removed from string.
Definition: CLI11.hpp:4765
bool get_enabled_by_default() const
Get the status of disabled by default.
Definition: CLI11.hpp:6859
App * excludes(App *app)
Sets excluded subcommands for the subcommand.
Definition: CLI11.hpp:6548
App * validate_positionals(bool validate=true)
Set the subcommand to validate positional arguments before assigning.
Definition: CLI11.hpp:5606
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition: CLI11.hpp:2665
bool get_ignore_underscore() const
Check the status of ignore_underscore.
Definition: CLI11.hpp:6805
const std::vector< std::string > & get_lnames() const
Get the long names.
Definition: CLI11.hpp:4544
Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition: CLI11.hpp:2741
bool remove_option(Option *opt)
Removes an option from the App. Takes an option pointer. Returns true if found and removed...
Definition: CLI11.hpp:6084
const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
Definition: CLI11.hpp:6897
T as() const
Return the results as the specified type.
Definition: CLI11.hpp:4894
App * positionals_at_end(bool value=true)
Specify that the positional arguments are only at the end of the sequence.
Definition: CLI11.hpp:5657
App * ignore_underscore(bool value=true)
Ignore underscore. Subcommands inherit value.
Definition: CLI11.hpp:5669
Option * type_name(std::string typeval)
Set a custom option typestring.
Definition: CLI11.hpp:4914
Option * type_size(int option_type_size_min, int option_type_size_max)
Set a custom option type size range.
Definition: CLI11.hpp:4939
Option * add_flag(std::string flag_name, std::vector< T > &flag_results, std::string flag_description="")
Vector version to capture multiple flags.
Definition: CLI11.hpp:6000
bool check_name(std::string name_to_check) const
Check the name, case insensitive and underscore insensitive if set.
Definition: CLI11.hpp:6923
Thrown when an excludes option is present.
Definition: CLI11.hpp:804
const Option * get_config_ptr() const
Get a pointer to the config option. (const)
Definition: CLI11.hpp:6879
const std::string & get_group() const
Get the group of this subcommand.
Definition: CLI11.hpp:6820
-v or –version on command line
Definition: CLI11.hpp:690
void _process_requirements()
Verify required options and cross requirements. Subcommands too (only if selected).
Definition: CLI11.hpp:7267
bool _valid_subcommand(const std::string &current, bool ignore_used=true) const
Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached...
Definition: CLI11.hpp:7110
Thrown when validation fails before parsing.
Definition: CLI11.hpp:837
App * require_option(int value)
Require an option to be given (does not affect help call) The number required can be given...
Definition: CLI11.hpp:6301
virtual std::string make_option_usage(const Option *opt) const
This is used to print the name on the USAGE line.
Definition: CLI11.hpp:8924
Option * ignore_case(bool value=true)
Ignore case.
Definition: CLI11.hpp:4449
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition: CLI11.hpp:3385
Holds values to load into Options.
Definition: CLI11.hpp:2519
std::string get_type_name() const
Get the full typename for this option.
Definition: CLI11.hpp:5014
This is the default Formatter for CLI11.
Definition: CLI11.hpp:3815
void add_options(Option *opt, Args... args)
Add a bunch of options to the group.
Definition: CLI11.hpp:8126
bool get_allow_extra_args() const
Get the current value of allow extra args.
Definition: CLI11.hpp:4278
CRTP * mandatory(bool value=true)
Support Plumbum term.
Definition: CLI11.hpp:3964
Definition: CLI11.hpp:1099
std::string make_help(const App *app, std::string name, AppFormatMode mode) const override
This will simply call the lambda function.
Definition: CLI11.hpp:3808
App * excludes(Option *opt)
Sets excluded options for the subcommand.
Definition: CLI11.hpp:6539
bool get_disabled_by_default() const
Get the status of disabled by default.
Definition: CLI11.hpp:6856
Check for an existing file (returns error message if check fails)
Definition: CLI11.hpp:2915
App * footer(std::function< std::string()> footer_function)
Set footer.
Definition: CLI11.hpp:6634
std::set< Option * > get_excludes() const
The set of options excluded.
Definition: CLI11.hpp:4535
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition: CLI11.hpp:2736
Option * add_flag(std::string flag_name, T &flag_result, std::string flag_description="")
Other type version accepts all other types that are not vectors such as bool, enum, string or other classes that can be converted from a string.
Definition: CLI11.hpp:5986
bool get_positional() const
True if the argument can be given directly.
Definition: CLI11.hpp:4584
MultiOptionPolicy get_multi_option_policy() const
The status of the multi option policy.
Definition: CLI11.hpp:3998
bool get_always_capture_default() const
Return true if this will automatically capture the default value for help printing.
Definition: CLI11.hpp:3995
void parse(std::vector< std::string > &&args)
The real work is done here. Expects a reversed vector.
Definition: CLI11.hpp:6429
bool get_ignore_underscore() const
The status of ignore_underscore.
Definition: CLI11.hpp:3983
void _validate() const
Check the options to make sure there are no conflicts.
Definition: CLI11.hpp:7024
Thrown on construction of a bad name.
Definition: CLI11.hpp:635
bool get_configurable() const
Check the status of the allow windows style options.
Definition: CLI11.hpp:6817
int get_items_expected_max() const
Get the maximum number of items expected to be returned and used for the callback.
Definition: CLI11.hpp:4576
Creates a command line program, with very few defaults.
Definition: CLI11.hpp:5213
App * group(std::string group_name)
Changes the group membership.
Definition: CLI11.hpp:6257
bool get_required() const
Get the status of required.
Definition: CLI11.hpp:6844
std::vector< App * > get_subcommands(const std::function< bool(App *)> &filter)
Get a filtered subcommand pointer list from the original definition list.
Definition: CLI11.hpp:6514
Option * get_option_no_throw(std::string option_name) noexcept
Get an option by name (noexcept non-const version)
Definition: CLI11.hpp:6740
std::string make_help(const App *, std::string, AppFormatMode) const override
This puts everything together.
Definition: CLI11.hpp:8788
Option * set_help_flag(std::string flag_name="", const std::string &help_description="")
Set a help flag, replace the existing one if present.
Definition: CLI11.hpp:5846
std::size_t count(std::string option_name) const
Counts the number of times the given option was passed.
Definition: CLI11.hpp:6488
const std::vector< std::string > & get_snames() const
Get the short names.
Definition: CLI11.hpp:4547
This converter works with INI/TOML files; to write INI files use ConfigINI.
Definition: CLI11.hpp:2571
int get_items_expected() const
The total min number of expected string values to be used.
Definition: CLI11.hpp:4581
App * require_subcommand(std::size_t min, std::size_t max)
Explicitly control the number of subcommands required.
Definition: CLI11.hpp:6285
CheckedTransformer(T mapping, F filter_function)
This checks to see if an item is in a set: pointer or copy version.
Definition: CLI11.hpp:3389
bool get_allow_windows_style_options() const
Check the status of the allow windows style options.
Definition: CLI11.hpp:6811
std::size_t get_column_width() const
Get the current column width.
Definition: CLI11.hpp:3788
std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
Definition: CLI11.hpp:6826
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition: CLI11.hpp:2678
std::string get_default_str() const
The default value (for help printing)
Definition: CLI11.hpp:4538
Thrown when extra values are found in an INI file.
Definition: CLI11.hpp:827
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition: CLI11.hpp:2655
bool remove_needs(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list...
Definition: CLI11.hpp:4387
Check to see if something is copyable pointer.
Definition: CLI11.hpp:911
-h or –help on command line
Definition: CLI11.hpp:677
Thrown when counting a non-existent option.
Definition: CLI11.hpp:854
Check for input streamability.
Definition: CLI11.hpp:1026
std::set< App * > exclude_subcommands_
this is a list of subcommands that are exclusionary to this one
Definition: CLI11.hpp:5317
virtual std::string make_positionals(const App *app) const
This prints out just the positionals "group".
Definition: CLI11.hpp:8678
std::shared_ptr< FormatterBase > get_formatter() const
Access the formatter.
Definition: CLI11.hpp:6682
std::string operator()(const std::string &str) const
This is the required operator for a Validator - provided to help users (CLI11 uses the member func di...
Definition: CLI11.hpp:2699
App * _get_fallthrough_parent()
Get the appropriate parent to fallthrough to which is the first one that has a name or the main app...
Definition: CLI11.hpp:7986
Option * add_result(std::string s, int &results_added)
Puts a result at the end and get a count of the number of arguments actually added.
Definition: CLI11.hpp:4825
App * parse_complete_callback(std::function< void()> pc_callback)
Set a callback to execute when parsing has completed for the app.
Definition: CLI11.hpp:5483
Option * needs(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition: CLI11.hpp:4381
Option * expected(int value)
Set the number of expected arguments.
Definition: CLI11.hpp:4231
char delimiter_
Specify a delimiter character for vector arguments.
Definition: CLI11.hpp:3927
const results_t & results() const
Get the current complete results set.
Definition: CLI11.hpp:4841
Definition: CLI11.hpp:987
Definition: CLI11.hpp:1080
Bound(T min, T max)
This bounds a value with min and max inclusive.
Definition: CLI11.hpp:3082
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Definition: CLI11.hpp:2821
App * _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept
Locate a subcommand by name with two conditions, should disabled subcommands be ignored, and should used subcommands be ignored.
Definition: CLI11.hpp:7760
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition: CLI11.hpp:2748
Option * default_str(std::string val)
Set the default value string representation (does not change the contained value) ...
Definition: CLI11.hpp:4981
Option * capture_default_str()
Capture the default value from the original value (if it can be captured)
Definition: CLI11.hpp:4973
std::set< Option * > get_needs() const
The set of options needed.
Definition: CLI11.hpp:4532
CRTP * take_all()
Set the multi option policy to take all arguments.
Definition: CLI11.hpp:4017
Option * add_result(std::string s)
Puts a result at the end.
Definition: CLI11.hpp:4818
std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
Definition: CLI11.hpp:6906
App * get_subcommand(const App *subcom) const
Check to see if a subcommand is part of this command (doesn&#39;t have to be in command line) returns the...
Definition: CLI11.hpp:6171
Option * add_option(Option *opt)
Add an existing option to the Option_group.
Definition: CLI11.hpp:8116
App * disabled_by_default(bool disable=true)
Set the subcommand to be disabled by default, so on clear(), at the start of each parse it is disable...
Definition: CLI11.hpp:5571
void parse(std::string commandline, bool program_name_included=false)
Parse a single string as if it contained command line arguments.
Definition: CLI11.hpp:6380
std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order)
Definition: CLI11.hpp:6952
std::string get_flag_value(const std::string &name, std::string input_value) const
Get the value that goes for a flag, nominally gets the default value but allows for overrides if not ...
Definition: CLI11.hpp:4774
virtual std::string make_expanded(const App *sub) const
This prints out a subcommand in help-all.
Definition: CLI11.hpp:8860
void _process()
Process callbacks and such.
Definition: CLI11.hpp:7396
Option * default_val(const X &val)
Set the default value and validate the results and run the callback if appropriate to set the value i...
Definition: CLI11.hpp:4988
void run_callback()
Process the callback.
Definition: CLI11.hpp:4676
App * fallthrough(bool value=true)
Stop subcommand fallthrough, so that parent commands cannot collect commands after subcommand...
Definition: CLI11.hpp:6322
Option * ignore_underscore(bool value=true)
Ignore underscores in the option names.
Definition: CLI11.hpp:4473
Validator & description(std::string validator_desc)
Specify the type string.
Definition: CLI11.hpp:2705
bool got_subcommand(std::string subcommand_name) const
Check with name instead of pointer to see if subcommand was selected.
Definition: CLI11.hpp:6536
const std::vector< std::string > & get_fnames() const
Get the flag names with specified default values.
Definition: CLI11.hpp:4550
const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const)
Definition: CLI11.hpp:6873
virtual std::string make_footer(const App *app) const
This prints out all the groups of options.
Definition: CLI11.hpp:8780
void _parse_config(const std::vector< ConfigItem > &args)
Parse one config param, return false if not found in any subcommand, remove if it is...
Definition: CLI11.hpp:7511
virtual void pre_callback()
This allows subclasses to inject code before callbacks but after parse.
Definition: CLI11.hpp:6338
Option * set_help_all_flag(std::string help_name="", const std::string &help_description="")
Set a help all flag, replaced the existing one if present.
Definition: CLI11.hpp:5863
void _process_help_flags(bool trigger_help=false, bool trigger_all_help=false) const
Run help flag processing if any are found.
Definition: CLI11.hpp:7244
bool get_active() const
Get a boolean if the validator is active.
Definition: CLI11.hpp:2766