args  6.2.0
A simple single-header C++11 STL-only argument parser library
args.hxx
Go to the documentation of this file.
1 /* A simple header-only C++ argument parser library.
2  *
3  * https://github.com/Taywee/args
4  *
5  * Copyright (c) 2016-2020 Taylor C. Richberger <taywee@gmx.com> and Pavel
6  * Belikov
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to
10  * deal in the Software without restriction, including without limitation the
11  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12  * sell copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24  * IN THE SOFTWARE.
25  */
26 
33 #ifndef ARGS_HXX
34 #define ARGS_HXX
35 
36 #define ARGS_VERSION "6.2.4"
37 #define ARGS_VERSION_MAJOR 6
38 #define ARGS_VERSION_MINOR 2
39 #define ARGS_VERSION_PATCH 4
40 
41 #include <algorithm>
42 #include <iterator>
43 #include <exception>
44 #include <functional>
45 #include <sstream>
46 #include <string>
47 #include <tuple>
48 #include <vector>
49 #include <unordered_map>
50 #include <unordered_set>
51 #include <type_traits>
52 #include <cstddef>
53 #include <iostream>
54 
55 #if defined(_MSC_VER) && _MSC_VER <= 1800
56 #define noexcept
57 #endif
58 
59 #ifdef ARGS_TESTNAMESPACE
60 namespace argstest
61 {
62 #else
63 
67 namespace args
68 {
69 #endif
75  template <typename Option>
76  auto get(Option &option_) -> decltype(option_.Get())
77  {
78  return option_.Get();
79  }
80 
89  inline std::string::size_type Glyphs(const std::string &string_)
90  {
91  std::string::size_type length = 0;
92  for (const char c: string_)
93  {
94  if ((c & 0xc0) != 0x80)
95  {
96  ++length;
97  }
98  }
99  return length;
100  }
101 
113  template <typename It>
114  inline std::vector<std::string> Wrap(It begin,
115  It end,
116  const std::string::size_type width,
117  std::string::size_type firstlinewidth = 0,
118  std::string::size_type firstlineindent = 0)
119  {
120  std::vector<std::string> output;
121  std::string line(firstlineindent, ' ');
122  bool empty = true;
123 
124  if (firstlinewidth == 0)
125  {
126  firstlinewidth = width;
127  }
128 
129  auto currentwidth = firstlinewidth;
130 
131  for (auto it = begin; it != end; ++it)
132  {
133  if (it->empty())
134  {
135  continue;
136  }
137 
138  if (*it == "\n")
139  {
140  if (!empty)
141  {
142  output.push_back(line);
143  line.clear();
144  empty = true;
145  currentwidth = width;
146  }
147 
148  continue;
149  }
150 
151  auto itemsize = Glyphs(*it);
152  if ((line.length() + 1 + itemsize) > currentwidth)
153  {
154  if (!empty)
155  {
156  output.push_back(line);
157  line.clear();
158  empty = true;
159  currentwidth = width;
160  }
161  }
162 
163  if (itemsize > 0)
164  {
165  if (!empty)
166  {
167  line += ' ';
168  }
169 
170  line += *it;
171  empty = false;
172  }
173  }
174 
175  if (!empty)
176  {
177  output.push_back(line);
178  }
179 
180  return output;
181  }
182 
183  namespace detail
184  {
185  template <typename T>
186  std::string Join(const T& array, const std::string &delimiter)
187  {
188  std::string res;
189  for (auto &element : array)
190  {
191  if (!res.empty())
192  {
193  res += delimiter;
194  }
195 
196  res += element;
197  }
198 
199  return res;
200  }
201  }
202 
212  inline std::vector<std::string> Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0)
213  {
214  // Preserve existing line breaks
215  const auto newlineloc = in.find('\n');
216  if (newlineloc != in.npos)
217  {
218  auto first = Wrap(std::string(in, 0, newlineloc), width);
219  auto second = Wrap(std::string(in, newlineloc + 1), width);
220  first.insert(
221  std::end(first),
222  std::make_move_iterator(std::begin(second)),
223  std::make_move_iterator(std::end(second)));
224  return first;
225  }
226 
227  std::istringstream stream(in);
228  std::string::size_type indent = 0;
229 
230  for (char c : in)
231  {
232  if (!isspace(c))
233  {
234  break;
235  }
236  ++indent;
237  }
238 
239  return Wrap(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>(),
240  width, firstlinewidth, indent);
241  }
242 
243 #ifdef ARGS_NOEXCEPT
245  enum class Error
246  {
247  None,
248  Usage,
249  Parse,
250  Validation,
251  Required,
252  Map,
253  Extra,
254  Help,
255  Subparser,
256  Completion,
257  };
258 #else
261  class Error : public std::runtime_error
262  {
263  public:
264  Error(const std::string &problem) : std::runtime_error(problem) {}
265  virtual ~Error() {}
266  };
267 
270  class UsageError : public Error
271  {
272  public:
273  UsageError(const std::string &problem) : Error(problem) {}
274  virtual ~UsageError() {}
275  };
276 
279  class ParseError : public Error
280  {
281  public:
282  ParseError(const std::string &problem) : Error(problem) {}
283  virtual ~ParseError() {}
284  };
285 
288  class ValidationError : public Error
289  {
290  public:
291  ValidationError(const std::string &problem) : Error(problem) {}
292  virtual ~ValidationError() {}
293  };
294 
298  {
299  public:
300  RequiredError(const std::string &problem) : ValidationError(problem) {}
301  virtual ~RequiredError() {}
302  };
303 
306  class MapError : public ParseError
307  {
308  public:
309  MapError(const std::string &problem) : ParseError(problem) {}
310  virtual ~MapError() {}
311  };
312 
315  class ExtraError : public ParseError
316  {
317  public:
318  ExtraError(const std::string &problem) : ParseError(problem) {}
319  virtual ~ExtraError() {}
320  };
321 
324  class Help : public Error
325  {
326  public:
327  Help(const std::string &flag) : Error(flag) {}
328  virtual ~Help() {}
329  };
330 
333  class SubparserError : public Error
334  {
335  public:
336  SubparserError() : Error("") {}
337  virtual ~SubparserError() {}
338  };
339 
342  class Completion : public Error
343  {
344  public:
345  Completion(const std::string &flag) : Error(flag) {}
346  virtual ~Completion() {}
347  };
348 #endif
349 
352  struct EitherFlag
353  {
354  const bool isShort;
355  const char shortFlag;
356  const std::string longFlag;
357  EitherFlag(const std::string &flag) : isShort(false), shortFlag(), longFlag(flag) {}
358  EitherFlag(const char *flag) : isShort(false), shortFlag(), longFlag(flag) {}
359  EitherFlag(const char flag) : isShort(true), shortFlag(flag), longFlag() {}
360 
363  static std::unordered_set<std::string> GetLong(std::initializer_list<EitherFlag> flags)
364  {
365  std::unordered_set<std::string> longFlags;
366  for (const EitherFlag &flag: flags)
367  {
368  if (!flag.isShort)
369  {
370  longFlags.insert(flag.longFlag);
371  }
372  }
373  return longFlags;
374  }
375 
378  static std::unordered_set<char> GetShort(std::initializer_list<EitherFlag> flags)
379  {
380  std::unordered_set<char> shortFlags;
381  for (const EitherFlag &flag: flags)
382  {
383  if (flag.isShort)
384  {
385  shortFlags.insert(flag.shortFlag);
386  }
387  }
388  return shortFlags;
389  }
390 
391  std::string str() const
392  {
393  return isShort ? std::string(1, shortFlag) : longFlag;
394  }
395 
396  std::string str(const std::string &shortPrefix, const std::string &longPrefix) const
397  {
398  return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag;
399  }
400  };
401 
402 
403 
410  class Matcher
411  {
412  private:
413  const std::unordered_set<char> shortFlags;
414  const std::unordered_set<std::string> longFlags;
415 
416  public:
421  template <typename ShortIt, typename LongIt>
422  Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd) :
423  shortFlags(shortFlagsStart, shortFlagsEnd),
424  longFlags(longFlagsStart, longFlagsEnd)
425  {
426  if (shortFlags.empty() && longFlags.empty())
427  {
428 #ifndef ARGS_NOEXCEPT
429  throw UsageError("empty Matcher");
430 #endif
431  }
432  }
433 
434 #ifdef ARGS_NOEXCEPT
436  Error GetError() const noexcept
437  {
438  return shortFlags.empty() && longFlags.empty() ? Error::Usage : Error::None;
439  }
440 #endif
441 
446  template <typename Short, typename Long>
447  Matcher(Short &&shortIn, Long &&longIn) :
448  Matcher(std::begin(shortIn), std::end(shortIn), std::begin(longIn), std::end(longIn))
449  {}
450 
463  Matcher(std::initializer_list<EitherFlag> in) :
464  Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {}
465 
466  Matcher(Matcher &&other) : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags))
467  {}
468 
469  ~Matcher() {}
470 
473  bool Match(const char flag) const
474  {
475  return shortFlags.find(flag) != shortFlags.end();
476  }
477 
480  bool Match(const std::string &flag) const
481  {
482  return longFlags.find(flag) != longFlags.end();
483  }
484 
487  bool Match(const EitherFlag &flag) const
488  {
489  return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag);
490  }
491 
494  std::vector<EitherFlag> GetFlagStrings() const
495  {
496  std::vector<EitherFlag> flagStrings;
497  flagStrings.reserve(shortFlags.size() + longFlags.size());
498  for (const char flag: shortFlags)
499  {
500  flagStrings.emplace_back(flag);
501  }
502  for (const std::string &flag: longFlags)
503  {
504  flagStrings.emplace_back(flag);
505  }
506  return flagStrings;
507  }
508 
512  {
513  if (!longFlags.empty())
514  {
515  return *longFlags.begin();
516  }
517 
518  if (!shortFlags.empty())
519  {
520  return *shortFlags.begin();
521  }
522 
523  // should be unreachable
524  return ' ';
525  }
526 
530  {
531  if (!shortFlags.empty())
532  {
533  return *shortFlags.begin();
534  }
535 
536  if (!longFlags.empty())
537  {
538  return *longFlags.begin();
539  }
540 
541  // should be unreachable
542  return ' ';
543  }
544  };
545 
548  enum class Options
549  {
552  None = 0x0,
553 
556  Single = 0x01,
557 
560  Required = 0x02,
561 
564  HiddenFromUsage = 0x04,
565 
568  HiddenFromDescription = 0x08,
569 
572  Global = 0x10,
573 
576  KickOut = 0x20,
577 
580  HiddenFromCompletion = 0x40,
581 
585  };
586 
587  inline Options operator | (Options lhs, Options rhs)
588  {
589  return static_cast<Options>(static_cast<int>(lhs) | static_cast<int>(rhs));
590  }
591 
592  inline Options operator & (Options lhs, Options rhs)
593  {
594  return static_cast<Options>(static_cast<int>(lhs) & static_cast<int>(rhs));
595  }
596 
597  class FlagBase;
598  class PositionalBase;
599  class Command;
600  class ArgumentParser;
601 
604  struct HelpParams
605  {
608  unsigned int width = 80;
611  unsigned int progindent = 2;
614  unsigned int progtailindent = 4;
617  unsigned int descriptionindent = 4;
620  unsigned int flagindent = 6;
623  unsigned int helpindent = 40;
626  unsigned int eachgroupindent = 2;
627 
630  unsigned int gutter = 1;
631 
634  bool showTerminator = true;
635 
638  bool showProglineOptions = true;
639 
642  bool showProglinePositionals = true;
643 
646  std::string shortPrefix;
647 
650  std::string longPrefix;
651 
654  std::string shortSeparator;
655 
658  std::string longSeparator;
659 
662  std::string programName;
663 
666  bool showCommandChildren = false;
667 
670  bool showCommandFullHelp = false;
671 
674  std::string proglineOptions = "{OPTIONS}";
675 
678  std::string proglineCommand = "COMMAND";
679 
682  std::string proglineValueOpen = " <";
683 
686  std::string proglineValueClose = ">";
687 
690  std::string proglineRequiredOpen = "";
691 
694  std::string proglineRequiredClose = "";
695 
698  std::string proglineNonrequiredOpen = "[";
699 
702  std::string proglineNonrequiredClose = "]";
703 
706  bool proglineShowFlags = false;
707 
710  bool proglinePreferShortFlags = false;
711 
714  std::string usageString;
715 
718  std::string optionsString = "OPTIONS:";
719 
722  bool useValueNameOnce = false;
723 
726  bool showValueName = true;
727 
730  bool addNewlineBeforeDescription = false;
731 
734  std::string valueOpen = "[";
735 
738  std::string valueClose = "]";
739 
742  bool addChoices = false;
743 
746  std::string choiceString = "\nOne of: ";
747 
750  bool addDefault = false;
751 
754  std::string defaultString = "\nDefault: ";
755  };
756 
761  struct Nargs
762  {
763  const size_t min;
764  const size_t max;
765 
766  Nargs(size_t min_, size_t max_) : min{min_}, max{max_}
767  {
768 #ifndef ARGS_NOEXCEPT
769  if (max < min)
770  {
771  throw UsageError("Nargs: max > min");
772  }
773 #endif
774  }
775 
776  Nargs(size_t num_) : min{num_}, max{num_}
777  {
778  }
779 
780  friend bool operator == (const Nargs &lhs, const Nargs &rhs)
781  {
782  return lhs.min == rhs.min && lhs.max == rhs.max;
783  }
784 
785  friend bool operator != (const Nargs &lhs, const Nargs &rhs)
786  {
787  return !(lhs == rhs);
788  }
789  };
790 
793  class Base
794  {
795  private:
796  Options options = {};
797 
798  protected:
799  bool matched = false;
800  const std::string help;
801 #ifdef ARGS_NOEXCEPT
803  mutable Error error = Error::None;
804  mutable std::string errorMsg;
805 #endif
806 
807  public:
808  Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {}
809  virtual ~Base() {}
810 
811  Options GetOptions() const noexcept
812  {
813  return options;
814  }
815 
816  bool IsRequired() const noexcept
817  {
818  return (GetOptions() & Options::Required) != Options::None;
819  }
820 
821  virtual bool Matched() const noexcept
822  {
823  return matched;
824  }
825 
826  virtual void Validate(const std::string &, const std::string &) const
827  {
828  }
829 
830  operator bool() const noexcept
831  {
832  return Matched();
833  }
834 
835  virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &, const unsigned indentLevel) const
836  {
837  std::tuple<std::string, std::string, unsigned> description;
838  std::get<1>(description) = help;
839  std::get<2>(description) = indentLevel;
840  return { std::move(description) };
841  }
842 
843  virtual std::vector<Command*> GetCommands()
844  {
845  return {};
846  }
847 
848  virtual bool IsGroup() const
849  {
850  return false;
851  }
852 
853  virtual FlagBase *Match(const EitherFlag &)
854  {
855  return nullptr;
856  }
857 
858  virtual PositionalBase *GetNextPositional()
859  {
860  return nullptr;
861  }
862 
863  virtual std::vector<FlagBase*> GetAllFlags()
864  {
865  return {};
866  }
867 
868  virtual bool HasFlag() const
869  {
870  return false;
871  }
872 
873  virtual bool HasPositional() const
874  {
875  return false;
876  }
877 
878  virtual bool HasCommand() const
879  {
880  return false;
881  }
882 
883  virtual std::vector<std::string> GetProgramLine(const HelpParams &) const
884  {
885  return {};
886  }
887 
889  void KickOut(bool kickout_) noexcept
890  {
891  if (kickout_)
892  {
893  options = options | Options::KickOut;
894  }
895  else
896  {
897  options = static_cast<Options>(static_cast<int>(options) & ~static_cast<int>(Options::KickOut));
898  }
899  }
900 
902  bool KickOut() const noexcept
903  {
904  return (options & Options::KickOut) != Options::None;
905  }
906 
907  virtual void Reset() noexcept
908  {
909  matched = false;
910 #ifdef ARGS_NOEXCEPT
911  error = Error::None;
912  errorMsg.clear();
913 #endif
914  }
915 
916 #ifdef ARGS_NOEXCEPT
918  virtual Error GetError() const
919  {
920  return error;
921  }
922 
924  std::string GetErrorMsg() const
925  {
926  return errorMsg;
927  }
928 #endif
929  };
930 
933  class NamedBase : public Base
934  {
935  protected:
936  const std::string name;
937  bool kickout = false;
938  std::string defaultString;
939  bool defaultStringManual = false;
940  std::vector<std::string> choicesStrings;
941  bool choicesStringManual = false;
942 
943  virtual std::string GetDefaultString(const HelpParams&) const { return {}; }
944 
945  virtual std::vector<std::string> GetChoicesStrings(const HelpParams&) const { return {}; }
946 
947  virtual std::string GetNameString(const HelpParams&) const { return Name(); }
948 
949  void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const
950  {
951  if (isManual && !manual.empty())
952  {
953  dest += str;
954  dest += manual;
955  }
956  else if (!isManual && isGenerated && !generated.empty())
957  {
958  dest += str;
959  dest += generated;
960  }
961  }
962 
963  public:
964  NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {}
965  virtual ~NamedBase() {}
966 
970  void HelpDefault(const std::string &str)
971  {
972  defaultStringManual = true;
973  defaultString = str;
974  }
975 
978  std::string HelpDefault(const HelpParams &params) const
979  {
980  return defaultStringManual ? defaultString : GetDefaultString(params);
981  }
982 
986  void HelpChoices(const std::vector<std::string> &array)
987  {
988  choicesStringManual = true;
989  choicesStrings = array;
990  }
991 
994  std::vector<std::string> HelpChoices(const HelpParams &params) const
995  {
996  return choicesStringManual ? choicesStrings : GetChoicesStrings(params);
997  }
998 
999  virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned indentLevel) const override
1000  {
1001  std::tuple<std::string, std::string, unsigned> description;
1002  std::get<0>(description) = GetNameString(params);
1003  std::get<1>(description) = help;
1004  std::get<2>(description) = indentLevel;
1005 
1006  AddDescriptionPostfix(std::get<1>(description), choicesStringManual, detail::Join(choicesStrings, ", "), params.addChoices, detail::Join(GetChoicesStrings(params), ", "), params.choiceString);
1007  AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString);
1008 
1009  return { std::move(description) };
1010  }
1011 
1012  virtual std::string Name() const
1013  {
1014  return name;
1015  }
1016  };
1017 
1018  namespace detail
1019  {
1020  template<typename T>
1021  using vector = std::vector<T, std::allocator<T>>;
1022 
1023  template<typename K, typename T>
1024  using unordered_map = std::unordered_map<K, T, std::hash<K>,
1025  std::equal_to<K>, std::allocator<std::pair<const K, T> > >;
1026 
1027  template<typename S, typename T>
1029  {
1030  template<typename SS, typename TT>
1031  static auto test(int)
1032  -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
1033 
1034  template<typename, typename>
1035  static auto test(...) -> std::false_type;
1036 
1037  public:
1038  using type = decltype(test<S,T>(0));
1039  };
1040 
1041  template <typename T>
1042  using IsConvertableToString = typename is_streamable<std::ostringstream, T>::type;
1043 
1044  template <typename T>
1045  typename std::enable_if<IsConvertableToString<T>::value, std::string>::type
1046  ToString(const T &value)
1047  {
1048  std::ostringstream s;
1049  s << value;
1050  return s.str();
1051  }
1052 
1053  template <typename T>
1054  typename std::enable_if<!IsConvertableToString<T>::value, std::string>::type
1055  ToString(const T &)
1056  {
1057  return {};
1058  }
1059 
1060  template <typename T>
1061  std::vector<std::string> MapKeysToStrings(const T &map)
1062  {
1063  std::vector<std::string> res;
1064  using K = typename std::decay<decltype(std::begin(map)->first)>::type;
1065  if (IsConvertableToString<K>::value)
1066  {
1067  for (const auto &p : map)
1068  {
1069  res.push_back(detail::ToString(p.first));
1070  }
1071 
1072  std::sort(res.begin(), res.end());
1073  }
1074  return res;
1075  }
1076  }
1077 
1080  class FlagBase : public NamedBase
1081  {
1082  protected:
1083  const Matcher matcher;
1084 
1085  virtual std::string GetNameString(const HelpParams &params) const override
1086  {
1087  const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name();
1088  std::string flags;
1089  const auto flagStrings = matcher.GetFlagStrings();
1090  const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce;
1091  for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it)
1092  {
1093  auto &flag = *it;
1094  if (it != flagStrings.begin())
1095  {
1096  flags += ", ";
1097  }
1098 
1099  flags += flag.isShort ? params.shortPrefix : params.longPrefix;
1100  flags += flag.str();
1101 
1102  if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end()))
1103  {
1104  flags += flag.isShort ? params.shortSeparator : params.longSeparator;
1105  flags += params.valueOpen + postfix + params.valueClose;
1106  }
1107  }
1108 
1109  return flags;
1110  }
1111 
1112  public:
1113  FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : NamedBase(name_, help_, extraError_ ? Options::Single : Options()), matcher(std::move(matcher_)) {}
1114 
1115  FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {}
1116 
1117  virtual ~FlagBase() {}
1118 
1119  virtual FlagBase *Match(const EitherFlag &flag) override
1120  {
1121  if (matcher.Match(flag))
1122  {
1123  if ((GetOptions() & Options::Single) != Options::None && matched)
1124  {
1125  std::ostringstream problem;
1126  problem << "Flag '" << flag.str() << "' was passed multiple times, but is only allowed to be passed once";
1127 #ifdef ARGS_NOEXCEPT
1128  error = Error::Extra;
1129  errorMsg = problem.str();
1130 #else
1131  throw ExtraError(problem.str());
1132 #endif
1133  }
1134  matched = true;
1135  return this;
1136  }
1137  return nullptr;
1138  }
1139 
1140  virtual std::vector<FlagBase*> GetAllFlags() override
1141  {
1142  return { this };
1143  }
1144 
1145  const Matcher &GetMatcher() const
1146  {
1147  return matcher;
1148  }
1149 
1150  virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1151  {
1152  if (!Matched() && IsRequired())
1153  {
1154  std::ostringstream problem;
1155  problem << "Flag '" << matcher.GetLongOrAny().str(shortPrefix, longPrefix) << "' is required";
1156 #ifdef ARGS_NOEXCEPT
1157  error = Error::Required;
1158  errorMsg = problem.str();
1159 #else
1160  throw RequiredError(problem.str());
1161 #endif
1162  }
1163  }
1164 
1165  virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1166  {
1167  if (!params.proglineShowFlags)
1168  {
1169  return {};
1170  }
1171 
1172  const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name();
1173  const EitherFlag flag = params.proglinePreferShortFlags ? matcher.GetShortOrAny() : matcher.GetLongOrAny();
1174  std::string res = flag.str(params.shortPrefix, params.longPrefix);
1175  if (!postfix.empty())
1176  {
1177  res += params.proglineValueOpen + postfix + params.proglineValueClose;
1178  }
1179 
1180  return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose
1181  : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose };
1182  }
1183 
1184  virtual bool HasFlag() const override
1185  {
1186  return true;
1187  }
1188 
1189 #ifdef ARGS_NOEXCEPT
1191  virtual Error GetError() const override
1192  {
1193  const auto nargs = NumberOfArguments();
1194  if (nargs.min > nargs.max)
1195  {
1196  return Error::Usage;
1197  }
1198 
1199  const auto matcherError = matcher.GetError();
1200  if (matcherError != Error::None)
1201  {
1202  return matcherError;
1203  }
1204 
1205  return error;
1206  }
1207 #endif
1208 
1213  virtual Nargs NumberOfArguments() const noexcept = 0;
1214 
1219  virtual void ParseValue(const std::vector<std::string> &value) = 0;
1220  };
1221 
1224  class ValueFlagBase : public FlagBase
1225  {
1226  public:
1227  ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : FlagBase(name_, help_, std::move(matcher_), extraError_) {}
1228  ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : FlagBase(name_, help_, std::move(matcher_), options_) {}
1229  virtual ~ValueFlagBase() {}
1230 
1231  virtual Nargs NumberOfArguments() const noexcept override
1232  {
1233  return 1;
1234  }
1235  };
1236 
1238  {
1239  public:
1240  std::vector<std::string> reply;
1241  size_t cword = 0;
1242  std::string syntax;
1243 
1244  template <typename GroupClass>
1245  CompletionFlag(GroupClass &group_, Matcher &&matcher_): ValueFlagBase("completion", "completion flag", std::move(matcher_), Options::Hidden)
1246  {
1247  group_.AddCompletion(*this);
1248  }
1249 
1250  virtual ~CompletionFlag() {}
1251 
1252  virtual Nargs NumberOfArguments() const noexcept override
1253  {
1254  return 2;
1255  }
1256 
1257  virtual void ParseValue(const std::vector<std::string> &value_) override
1258  {
1259  syntax = value_.at(0);
1260  std::istringstream(value_.at(1)) >> cword;
1261  }
1262 
1265  std::string Get() noexcept
1266  {
1267  return detail::Join(reply, "\n");
1268  }
1269 
1270  virtual void Reset() noexcept override
1271  {
1272  ValueFlagBase::Reset();
1273  cword = 0;
1274  syntax.clear();
1275  reply.clear();
1276  }
1277  };
1278 
1279 
1282  class PositionalBase : public NamedBase
1283  {
1284  protected:
1285  bool ready;
1286 
1287  public:
1288  PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {}
1289  virtual ~PositionalBase() {}
1290 
1291  bool Ready()
1292  {
1293  return ready;
1294  }
1295 
1296  virtual void ParseValue(const std::string &value_) = 0;
1297 
1298  virtual void Reset() noexcept override
1299  {
1300  matched = false;
1301  ready = true;
1302 #ifdef ARGS_NOEXCEPT
1303  error = Error::None;
1304  errorMsg.clear();
1305 #endif
1306  }
1307 
1308  virtual PositionalBase *GetNextPositional() override
1309  {
1310  return Ready() ? this : nullptr;
1311  }
1312 
1313  virtual bool HasPositional() const override
1314  {
1315  return true;
1316  }
1317 
1318  virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1319  {
1320  return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose
1321  : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose };
1322  }
1323 
1324  virtual void Validate(const std::string &, const std::string &) const override
1325  {
1326  if (IsRequired() && !Matched())
1327  {
1328  std::ostringstream problem;
1329  problem << "Option '" << Name() << "' is required";
1330 #ifdef ARGS_NOEXCEPT
1331  error = Error::Required;
1332  errorMsg = problem.str();
1333 #else
1334  throw RequiredError(problem.str());
1335 #endif
1336  }
1337  }
1338  };
1339 
1342  class Group : public Base
1343  {
1344  private:
1345  std::vector<Base*> children;
1346  std::function<bool(const Group &)> validator;
1347 
1348  public:
1351  struct Validators
1352  {
1353  static bool Xor(const Group &group)
1354  {
1355  return group.MatchedChildren() == 1;
1356  }
1357 
1358  static bool AtLeastOne(const Group &group)
1359  {
1360  return group.MatchedChildren() >= 1;
1361  }
1362 
1363  static bool AtMostOne(const Group &group)
1364  {
1365  return group.MatchedChildren() <= 1;
1366  }
1367 
1368  static bool All(const Group &group)
1369  {
1370  return group.Children().size() == group.MatchedChildren();
1371  }
1372 
1373  static bool AllOrNone(const Group &group)
1374  {
1375  return (All(group) || None(group));
1376  }
1377 
1378  static bool AllChildGroups(const Group &group)
1379  {
1380  return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool {
1381  return child->IsGroup() && !child->Matched();
1382  });
1383  }
1384 
1385  static bool DontCare(const Group &)
1386  {
1387  return true;
1388  }
1389 
1390  static bool CareTooMuch(const Group &)
1391  {
1392  return false;
1393  }
1394 
1395  static bool None(const Group &group)
1396  {
1397  return group.MatchedChildren() == 0;
1398  }
1399  };
1401  Group(const std::string &help_ = std::string(), const std::function<bool(const Group &)> &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) {}
1403  Group(Group &group_, const std::string &help_ = std::string(), const std::function<bool(const Group &)> &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_)
1404  {
1405  group_.Add(*this);
1406  }
1407  virtual ~Group() {}
1408 
1411  void Add(Base &child)
1412  {
1413  children.emplace_back(&child);
1414  }
1415 
1418  const std::vector<Base *> &Children() const
1419  {
1420  return children;
1421  }
1422 
1428  virtual FlagBase *Match(const EitherFlag &flag) override
1429  {
1430  for (Base *child: Children())
1431  {
1432  if (FlagBase *match = child->Match(flag))
1433  {
1434  return match;
1435  }
1436  }
1437  return nullptr;
1438  }
1439 
1440  virtual std::vector<FlagBase*> GetAllFlags() override
1441  {
1442  std::vector<FlagBase*> res;
1443  for (Base *child: Children())
1444  {
1445  auto childRes = child->GetAllFlags();
1446  res.insert(res.end(), childRes.begin(), childRes.end());
1447  }
1448  return res;
1449  }
1450 
1451  virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1452  {
1453  for (Base *child: Children())
1454  {
1455  child->Validate(shortPrefix, longPrefix);
1456  }
1457  }
1458 
1463  virtual PositionalBase *GetNextPositional() override
1464  {
1465  for (Base *child: Children())
1466  {
1467  if (auto next = child->GetNextPositional())
1468  {
1469  return next;
1470  }
1471  }
1472  return nullptr;
1473  }
1474 
1479  virtual bool HasFlag() const override
1480  {
1481  return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); });
1482  }
1483 
1488  virtual bool HasPositional() const override
1489  {
1490  return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); });
1491  }
1492 
1497  virtual bool HasCommand() const override
1498  {
1499  return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); });
1500  }
1501 
1504  std::vector<Base *>::size_type MatchedChildren() const
1505  {
1506  // Cast to avoid warnings from -Wsign-conversion
1507  return static_cast<std::vector<Base *>::size_type>(
1508  std::count_if(std::begin(Children()), std::end(Children()), [](const Base *child){return child->Matched();}));
1509  }
1510 
1513  virtual bool Matched() const noexcept override
1514  {
1515  return validator(*this);
1516  }
1517 
1520  bool Get() const
1521  {
1522  return Matched();
1523  }
1524 
1527  virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
1528  {
1529  std::vector<std::tuple<std::string, std::string, unsigned int>> descriptions;
1530 
1531  // Push that group description on the back if not empty
1532  unsigned addindent = 0;
1533  if (!help.empty())
1534  {
1535  descriptions.emplace_back(help, "", indent);
1536  addindent = 1;
1537  }
1538 
1539  for (Base *child: Children())
1540  {
1541  if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
1542  {
1543  continue;
1544  }
1545 
1546  auto groupDescriptions = child->GetDescription(params, indent + addindent);
1547  descriptions.insert(
1548  std::end(descriptions),
1549  std::make_move_iterator(std::begin(groupDescriptions)),
1550  std::make_move_iterator(std::end(groupDescriptions)));
1551  }
1552  return descriptions;
1553  }
1554 
1557  virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1558  {
1559  std::vector <std::string> names;
1560  for (Base *child: Children())
1561  {
1562  if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None)
1563  {
1564  continue;
1565  }
1566 
1567  auto groupNames = child->GetProgramLine(params);
1568  names.insert(
1569  std::end(names),
1570  std::make_move_iterator(std::begin(groupNames)),
1571  std::make_move_iterator(std::end(groupNames)));
1572  }
1573  return names;
1574  }
1575 
1576  virtual std::vector<Command*> GetCommands() override
1577  {
1578  std::vector<Command*> res;
1579  for (const auto &child : Children())
1580  {
1581  auto subparsers = child->GetCommands();
1582  res.insert(std::end(res), std::begin(subparsers), std::end(subparsers));
1583  }
1584  return res;
1585  }
1586 
1587  virtual bool IsGroup() const override
1588  {
1589  return true;
1590  }
1591 
1592  virtual void Reset() noexcept override
1593  {
1594  Base::Reset();
1595 
1596  for (auto &child: Children())
1597  {
1598  child->Reset();
1599  }
1600 #ifdef ARGS_NOEXCEPT
1601  error = Error::None;
1602  errorMsg.clear();
1603 #endif
1604  }
1605 
1606 #ifdef ARGS_NOEXCEPT
1608  virtual Error GetError() const override
1609  {
1610  if (error != Error::None)
1611  {
1612  return error;
1613  }
1614 
1615  auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;});
1616  if (it == Children().end())
1617  {
1618  return Error::None;
1619  } else
1620  {
1621  return (*it)->GetError();
1622  }
1623  }
1624 #endif
1625 
1626  };
1627 
1630  class GlobalOptions : public Group
1631  {
1632  public:
1633  GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global)
1634  {
1635  Add(options_);
1636  }
1637  };
1638 
1656  class Subparser : public Group
1657  {
1658  private:
1659  std::vector<std::string> args;
1660  std::vector<std::string> kicked;
1661  ArgumentParser *parser = nullptr;
1662  const HelpParams &helpParams;
1663  const Command &command;
1664  bool isParsed = false;
1665 
1666  public:
1667  Subparser(std::vector<std::string> args_, ArgumentParser &parser_, const Command &command_, const HelpParams &helpParams_)
1668  : Group({}, Validators::AllChildGroups), args(std::move(args_)), parser(&parser_), helpParams(helpParams_), command(command_)
1669  {
1670  }
1671 
1672  Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_)
1673  {
1674  }
1675 
1676  Subparser(const Subparser&) = delete;
1677  Subparser(Subparser&&) = delete;
1678  Subparser &operator = (const Subparser&) = delete;
1679  Subparser &operator = (Subparser&&) = delete;
1680 
1681  const Command &GetCommand()
1682  {
1683  return command;
1684  }
1685 
1688  bool IsParsed() const
1689  {
1690  return isParsed;
1691  }
1692 
1695  void Parse();
1696 
1701  const std::vector<std::string> &KickedOut() const noexcept
1702  {
1703  return kicked;
1704  }
1705  };
1706 
1711  class Command : public Group
1712  {
1713  private:
1714  friend class Subparser;
1715 
1716  std::string name;
1717  std::string help;
1718  std::string description;
1719  std::string epilog;
1720  std::string proglinePostfix;
1721 
1722  std::function<void(Subparser&)> parserCoroutine;
1723  bool commandIsRequired = true;
1724  Command *selectedCommand = nullptr;
1725 
1726  mutable std::vector<std::tuple<std::string, std::string, unsigned>> subparserDescription;
1727  mutable std::vector<std::string> subparserProgramLine;
1728  mutable bool subparserHasFlag = false;
1729  mutable bool subparserHasPositional = false;
1730  mutable bool subparserHasCommand = false;
1731 #ifdef ARGS_NOEXCEPT
1732  mutable Error subparserError = Error::None;
1733 #endif
1734  mutable Subparser *subparser = nullptr;
1735 
1736  protected:
1737 
1738  class RaiiSubparser
1739  {
1740  public:
1741  RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_);
1742  RaiiSubparser(const Command &command_, const HelpParams &params_);
1743 
1744  ~RaiiSubparser()
1745  {
1746  command.subparser = oldSubparser;
1747  }
1748 
1749  Subparser &Parser()
1750  {
1751  return parser;
1752  }
1753 
1754  private:
1755  const Command &command;
1756  Subparser parser;
1757  Subparser *oldSubparser;
1758  };
1759 
1760  Command() = default;
1761 
1762  std::function<void(Subparser&)> &GetCoroutine()
1763  {
1764  return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine;
1765  }
1766 
1767  Command &SelectedCommand()
1768  {
1769  Command *res = this;
1770  while (res->selectedCommand != nullptr)
1771  {
1772  res = res->selectedCommand;
1773  }
1774 
1775  return *res;
1776  }
1777 
1778  const Command &SelectedCommand() const
1779  {
1780  const Command *res = this;
1781  while (res->selectedCommand != nullptr)
1782  {
1783  res = res->selectedCommand;
1784  }
1785 
1786  return *res;
1787  }
1788 
1789  void UpdateSubparserHelp(const HelpParams &params) const
1790  {
1791  if (parserCoroutine)
1792  {
1793  RaiiSubparser coro(*this, params);
1794 #ifndef ARGS_NOEXCEPT
1795  try
1796  {
1797  parserCoroutine(coro.Parser());
1798  }
1799  catch (args::SubparserError&)
1800  {
1801  }
1802 #else
1803  parserCoroutine(coro.Parser());
1804 #endif
1805  }
1806  }
1807 
1808  public:
1809  Command(Group &base_, std::string name_, std::string help_, std::function<void(Subparser&)> coroutine_ = {})
1810  : name(std::move(name_)), help(std::move(help_)), parserCoroutine(std::move(coroutine_))
1811  {
1812  base_.Add(*this);
1813  }
1814 
1817  const std::string &ProglinePostfix() const
1818  { return proglinePostfix; }
1819 
1822  void ProglinePostfix(const std::string &proglinePostfix_)
1823  { this->proglinePostfix = proglinePostfix_; }
1824 
1827  const std::string &Description() const
1828  { return description; }
1832  void Description(const std::string &description_)
1833  { this->description = description_; }
1834 
1837  const std::string &Epilog() const
1838  { return epilog; }
1839 
1842  void Epilog(const std::string &epilog_)
1843  { this->epilog = epilog_; }
1844 
1847  const std::string &Name() const
1848  { return name; }
1849 
1852  const std::string &Help() const
1853  { return help; }
1854 
1859  void RequireCommand(bool value)
1860  { commandIsRequired = value; }
1861 
1862  virtual bool IsGroup() const override
1863  { return false; }
1864 
1865  virtual bool Matched() const noexcept override
1866  { return Base::Matched(); }
1867 
1868  operator bool() const noexcept
1869  { return Matched(); }
1870 
1871  void Match() noexcept
1872  { matched = true; }
1873 
1874  void SelectCommand(Command *c) noexcept
1875  {
1876  selectedCommand = c;
1877 
1878  if (c != nullptr)
1879  {
1880  c->Match();
1881  }
1882  }
1883 
1884  virtual FlagBase *Match(const EitherFlag &flag) override
1885  {
1886  if (selectedCommand != nullptr)
1887  {
1888  if (auto *res = selectedCommand->Match(flag))
1889  {
1890  return res;
1891  }
1892 
1893  for (auto *child: Children())
1894  {
1895  if ((child->GetOptions() & Options::Global) != Options::None)
1896  {
1897  if (auto *res = child->Match(flag))
1898  {
1899  return res;
1900  }
1901  }
1902  }
1903 
1904  return nullptr;
1905  }
1906 
1907  if (subparser != nullptr)
1908  {
1909  return subparser->Match(flag);
1910  }
1911 
1912  return Matched() ? Group::Match(flag) : nullptr;
1913  }
1914 
1915  virtual std::vector<FlagBase*> GetAllFlags() override
1916  {
1917  std::vector<FlagBase*> res;
1918 
1919  if (!Matched())
1920  {
1921  return res;
1922  }
1923 
1924  for (auto *child: Children())
1925  {
1926  if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None)
1927  {
1928  auto childFlags = child->GetAllFlags();
1929  res.insert(res.end(), childFlags.begin(), childFlags.end());
1930  }
1931  }
1932 
1933  if (selectedCommand != nullptr)
1934  {
1935  auto childFlags = selectedCommand->GetAllFlags();
1936  res.insert(res.end(), childFlags.begin(), childFlags.end());
1937  }
1938 
1939  if (subparser != nullptr)
1940  {
1941  auto childFlags = subparser->GetAllFlags();
1942  res.insert(res.end(), childFlags.begin(), childFlags.end());
1943  }
1944 
1945  return res;
1946  }
1947 
1948  virtual PositionalBase *GetNextPositional() override
1949  {
1950  if (selectedCommand != nullptr)
1951  {
1952  if (auto *res = selectedCommand->GetNextPositional())
1953  {
1954  return res;
1955  }
1956 
1957  for (auto *child: Children())
1958  {
1959  if ((child->GetOptions() & Options::Global) != Options::None)
1960  {
1961  if (auto *res = child->GetNextPositional())
1962  {
1963  return res;
1964  }
1965  }
1966  }
1967 
1968  return nullptr;
1969  }
1970 
1971  if (subparser != nullptr)
1972  {
1973  return subparser->GetNextPositional();
1974  }
1975 
1976  return Matched() ? Group::GetNextPositional() : nullptr;
1977  }
1978 
1979  virtual bool HasFlag() const override
1980  {
1981  return subparserHasFlag || Group::HasFlag();
1982  }
1983 
1984  virtual bool HasPositional() const override
1985  {
1986  return subparserHasPositional || Group::HasPositional();
1987  }
1988 
1989  virtual bool HasCommand() const override
1990  {
1991  return true;
1992  }
1993 
1994  std::vector<std::string> GetCommandProgramLine(const HelpParams &params) const
1995  {
1996  UpdateSubparserHelp(params);
1997 
1998  auto res = Group::GetProgramLine(params);
1999  res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end());
2000 
2001  if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand))
2002  {
2003  res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]");
2004  }
2005 
2006  if (!Name().empty())
2007  {
2008  res.insert(res.begin(), Name());
2009  }
2010 
2011  if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags)
2012  {
2013  res.push_back(params.proglineOptions);
2014  }
2015 
2016  if (!ProglinePostfix().empty())
2017  {
2018  std::string line;
2019  for (char c : ProglinePostfix())
2020  {
2021  if (isspace(c))
2022  {
2023  if (!line.empty())
2024  {
2025  res.push_back(line);
2026  line.clear();
2027  }
2028 
2029  if (c == '\n')
2030  {
2031  res.push_back("\n");
2032  }
2033  }
2034  else
2035  {
2036  line += c;
2037  }
2038  }
2039 
2040  if (!line.empty())
2041  {
2042  res.push_back(line);
2043  }
2044  }
2045 
2046  return res;
2047  }
2048 
2049  virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
2050  {
2051  if (!Matched())
2052  {
2053  return {};
2054  }
2055 
2056  return GetCommandProgramLine(params);
2057  }
2058 
2059  virtual std::vector<Command*> GetCommands() override
2060  {
2061  if (selectedCommand != nullptr)
2062  {
2063  return selectedCommand->GetCommands();
2064  }
2065 
2066  if (Matched())
2067  {
2068  return Group::GetCommands();
2069  }
2070 
2071  return { this };
2072  }
2073 
2074  virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
2075  {
2076  std::vector<std::tuple<std::string, std::string, unsigned>> descriptions;
2077  unsigned addindent = 0;
2078 
2079  UpdateSubparserHelp(params);
2080 
2081  if (!Matched())
2082  {
2083  if (params.showCommandFullHelp)
2084  {
2085  std::ostringstream s;
2086  bool empty = true;
2087  for (const auto &progline: GetCommandProgramLine(params))
2088  {
2089  if (!empty)
2090  {
2091  s << ' ';
2092  }
2093  else
2094  {
2095  empty = false;
2096  }
2097 
2098  s << progline;
2099  }
2100 
2101  descriptions.emplace_back(s.str(), "", indent);
2102  }
2103  else
2104  {
2105  descriptions.emplace_back(Name(), help, indent);
2106  }
2107 
2108  if (!params.showCommandChildren && !params.showCommandFullHelp)
2109  {
2110  return descriptions;
2111  }
2112 
2113  addindent = 1;
2114  }
2115 
2116  if (params.showCommandFullHelp && !Matched())
2117  {
2118  descriptions.emplace_back("", "", indent + addindent);
2119  descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent);
2120  descriptions.emplace_back("", "", indent + addindent);
2121  }
2122 
2123  for (Base *child: Children())
2124  {
2125  if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
2126  {
2127  continue;
2128  }
2129 
2130  auto groupDescriptions = child->GetDescription(params, indent + addindent);
2131  descriptions.insert(
2132  std::end(descriptions),
2133  std::make_move_iterator(std::begin(groupDescriptions)),
2134  std::make_move_iterator(std::end(groupDescriptions)));
2135  }
2136 
2137  for (auto childDescription: subparserDescription)
2138  {
2139  std::get<2>(childDescription) += indent + addindent;
2140  descriptions.push_back(std::move(childDescription));
2141  }
2142 
2143  if (params.showCommandFullHelp && !Matched())
2144  {
2145  descriptions.emplace_back("", "", indent + addindent);
2146  if (!Epilog().empty())
2147  {
2148  descriptions.emplace_back(Epilog(), "", indent + addindent);
2149  descriptions.emplace_back("", "", indent + addindent);
2150  }
2151  }
2152 
2153  return descriptions;
2154  }
2155 
2156  virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override
2157  {
2158  if (!Matched())
2159  {
2160  return;
2161  }
2162 
2163  auto onValidationError = [&]
2164  {
2165  std::ostringstream problem;
2166  problem << "Group validation failed somewhere!";
2167 #ifdef ARGS_NOEXCEPT
2168  error = Error::Validation;
2169  errorMsg = problem.str();
2170 #else
2171  throw ValidationError(problem.str());
2172 #endif
2173  };
2174 
2175  for (Base *child: Children())
2176  {
2177  if (child->IsGroup() && !child->Matched())
2178  {
2179  onValidationError();
2180  }
2181 
2182  child->Validate(shortprefix, longprefix);
2183  }
2184 
2185  if (subparser != nullptr)
2186  {
2187  subparser->Validate(shortprefix, longprefix);
2188  if (!subparser->Matched())
2189  {
2190  onValidationError();
2191  }
2192  }
2193 
2194  if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand))
2195  {
2196  std::ostringstream problem;
2197  problem << "Command is required";
2198 #ifdef ARGS_NOEXCEPT
2199  error = Error::Validation;
2200  errorMsg = problem.str();
2201 #else
2202  throw ValidationError(problem.str());
2203 #endif
2204  }
2205  }
2206 
2207  virtual void Reset() noexcept override
2208  {
2209  Group::Reset();
2210  selectedCommand = nullptr;
2211  subparserProgramLine.clear();
2212  subparserDescription.clear();
2213  subparserHasFlag = false;
2214  subparserHasPositional = false;
2215  subparserHasCommand = false;
2216 #ifdef ARGS_NOEXCEPT
2217  subparserError = Error::None;
2218 #endif
2219  }
2220 
2221 #ifdef ARGS_NOEXCEPT
2223  virtual Error GetError() const override
2224  {
2225  if (!Matched())
2226  {
2227  return Error::None;
2228  }
2229 
2230  if (error != Error::None)
2231  {
2232  return error;
2233  }
2234 
2235  if (subparserError != Error::None)
2236  {
2237  return subparserError;
2238  }
2239 
2240  return Group::GetError();
2241  }
2242 #endif
2243  };
2244 
2247  class ArgumentParser : public Command
2248  {
2249  friend class Subparser;
2250 
2251  private:
2252  std::string longprefix;
2253  std::string shortprefix;
2254 
2255  std::string longseparator;
2256 
2257  std::string terminator;
2258 
2259  bool allowJoinedShortValue = true;
2260  bool allowJoinedLongValue = true;
2261  bool allowSeparateShortValue = true;
2262  bool allowSeparateLongValue = true;
2263 
2264  CompletionFlag *completion = nullptr;
2265  bool readCompletion = false;
2266 
2267  protected:
2268  enum class OptionType
2269  {
2270  LongFlag,
2271  ShortFlag,
2272  Positional
2273  };
2274 
2275  OptionType ParseOption(const std::string &s, bool allowEmpty = false)
2276  {
2277  if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length()))
2278  {
2279  return OptionType::LongFlag;
2280  }
2281 
2282  if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length()))
2283  {
2284  return OptionType::ShortFlag;
2285  }
2286 
2287  return OptionType::Positional;
2288  }
2289 
2290  template <typename It>
2291  bool Complete(FlagBase &flag, It it, It end)
2292  {
2293  auto nextIt = it;
2294  if (!readCompletion || (++nextIt != end))
2295  {
2296  return false;
2297  }
2298 
2299  const auto &chunk = *it;
2300  for (auto &choice : flag.HelpChoices(helpParams))
2301  {
2302  AddCompletionReply(chunk, choice);
2303  }
2304 
2305 #ifndef ARGS_NOEXCEPT
2306  throw Completion(completion->Get());
2307 #else
2308  return true;
2309 #endif
2310  }
2311 
2321  template <typename It>
2322  std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end,
2323  const bool allowSeparate, const bool allowJoined,
2324  const bool hasJoined, const std::string &joinedArg,
2325  const bool canDiscardJoined, std::vector<std::string> &values)
2326  {
2327  values.clear();
2328 
2329  Nargs nargs = flag.NumberOfArguments();
2330 
2331  if (hasJoined && !allowJoined && nargs.min != 0)
2332  {
2333  return "Flag '" + arg + "' was passed a joined argument, but these are disallowed";
2334  }
2335 
2336  if (hasJoined)
2337  {
2338  if (!canDiscardJoined || nargs.max != 0)
2339  {
2340  values.push_back(joinedArg);
2341  }
2342  } else if (!allowSeparate)
2343  {
2344  if (nargs.min != 0)
2345  {
2346  return "Flag '" + arg + "' was passed a separate argument, but these are disallowed";
2347  }
2348  } else
2349  {
2350  auto valueIt = it;
2351  ++valueIt;
2352 
2353  while (valueIt != end &&
2354  values.size() < nargs.max &&
2355  (values.size() < nargs.min || ParseOption(*valueIt) == OptionType::Positional))
2356  {
2357  if (Complete(flag, valueIt, end))
2358  {
2359  it = end;
2360  return "";
2361  }
2362 
2363  values.push_back(*valueIt);
2364  ++it;
2365  ++valueIt;
2366  }
2367  }
2368 
2369  if (values.size() > nargs.max)
2370  {
2371  return "Passed an argument into a non-argument flag: " + arg;
2372  } else if (values.size() < nargs.min)
2373  {
2374  if (nargs.min == 1 && nargs.max == 1)
2375  {
2376  return "Flag '" + arg + "' requires an argument but received none";
2377  } else if (nargs.min == 1)
2378  {
2379  return "Flag '" + arg + "' requires at least one argument but received none";
2380  } else if (nargs.min != nargs.max)
2381  {
2382  return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) +
2383  " arguments but received " + std::to_string(values.size());
2384  } else
2385  {
2386  return "Flag '" + arg + "' requires " + std::to_string(nargs.min) +
2387  " arguments but received " + std::to_string(values.size());
2388  }
2389  }
2390 
2391  return {};
2392  }
2393 
2394  template <typename It>
2395  bool ParseLong(It &it, It end)
2396  {
2397  const auto &chunk = *it;
2398  const auto argchunk = chunk.substr(longprefix.size());
2399  // Try to separate it, in case of a separator:
2400  const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator);
2401  // If the separator is in the argument, separate it.
2402  const auto arg = (separator != argchunk.npos ?
2403  std::string(argchunk, 0, separator)
2404  : argchunk);
2405  const auto joined = (separator != argchunk.npos ?
2406  argchunk.substr(separator + longseparator.size())
2407  : std::string());
2408 
2409  if (auto flag = Match(arg))
2410  {
2411  std::vector<std::string> values;
2412  const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue,
2413  separator != argchunk.npos, joined, false, values);
2414  if (!errorMessage.empty())
2415  {
2416 #ifndef ARGS_NOEXCEPT
2417  throw ParseError(errorMessage);
2418 #else
2419  error = Error::Parse;
2420  errorMsg = errorMessage;
2421  return false;
2422 #endif
2423  }
2424 
2425  if (!readCompletion)
2426  {
2427  flag->ParseValue(values);
2428  }
2429 
2430  if (flag->KickOut())
2431  {
2432  ++it;
2433  return false;
2434  }
2435  } else
2436  {
2437  const std::string errorMessage("Flag could not be matched: " + arg);
2438 #ifndef ARGS_NOEXCEPT
2439  throw ParseError(errorMessage);
2440 #else
2441  error = Error::Parse;
2442  errorMsg = errorMessage;
2443  return false;
2444 #endif
2445  }
2446 
2447  return true;
2448  }
2449 
2450  template <typename It>
2451  bool ParseShort(It &it, It end)
2452  {
2453  const auto &chunk = *it;
2454  const auto argchunk = chunk.substr(shortprefix.size());
2455  for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit)
2456  {
2457  const auto arg = *argit;
2458 
2459  if (auto flag = Match(arg))
2460  {
2461  const std::string value(argit + 1, std::end(argchunk));
2462  std::vector<std::string> values;
2463  const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end,
2464  allowSeparateShortValue, allowJoinedShortValue,
2465  !value.empty(), value, !value.empty(), values);
2466 
2467  if (!errorMessage.empty())
2468  {
2469 #ifndef ARGS_NOEXCEPT
2470  throw ParseError(errorMessage);
2471 #else
2472  error = Error::Parse;
2473  errorMsg = errorMessage;
2474  return false;
2475 #endif
2476  }
2477 
2478  if (!readCompletion)
2479  {
2480  flag->ParseValue(values);
2481  }
2482 
2483  if (flag->KickOut())
2484  {
2485  ++it;
2486  return false;
2487  }
2488 
2489  if (!values.empty())
2490  {
2491  break;
2492  }
2493  } else
2494  {
2495  const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'");
2496 #ifndef ARGS_NOEXCEPT
2497  throw ParseError(errorMessage);
2498 #else
2499  error = Error::Parse;
2500  errorMsg = errorMessage;
2501  return false;
2502 #endif
2503  }
2504  }
2505 
2506  return true;
2507  }
2508 
2509  bool AddCompletionReply(const std::string &cur, const std::string &choice)
2510  {
2511  if (cur.empty() || choice.find(cur) == 0)
2512  {
2513  if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos)
2514  {
2515  completion->reply.push_back(choice.substr(choice.find(longseparator) + 1));
2516  } else
2517  {
2518  completion->reply.push_back(choice);
2519  }
2520  return true;
2521  }
2522 
2523  return false;
2524  }
2525 
2526  template <typename It>
2527  bool Complete(It it, It end)
2528  {
2529  auto nextIt = it;
2530  if (!readCompletion || (++nextIt != end))
2531  {
2532  return false;
2533  }
2534 
2535  const auto &chunk = *it;
2536  auto pos = GetNextPositional();
2537  std::vector<Command *> commands = GetCommands();
2538  const auto optionType = ParseOption(chunk, true);
2539 
2540  if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
2541  {
2542  for (auto &cmd : commands)
2543  {
2544  if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2545  {
2546  AddCompletionReply(chunk, cmd->Name());
2547  }
2548  }
2549  } else
2550  {
2551  bool hasPositionalCompletion = true;
2552 
2553  if (!commands.empty())
2554  {
2555  for (auto &cmd : commands)
2556  {
2557  if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2558  {
2559  AddCompletionReply(chunk, cmd->Name());
2560  }
2561  }
2562  } else if (pos)
2563  {
2564  if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2565  {
2566  auto choices = pos->HelpChoices(helpParams);
2567  hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
2568  for (auto &choice : choices)
2569  {
2570  AddCompletionReply(chunk, choice);
2571  }
2572  }
2573  }
2574 
2575  if (hasPositionalCompletion)
2576  {
2577  auto flags = GetAllFlags();
2578  for (auto flag : flags)
2579  {
2580  if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None)
2581  {
2582  continue;
2583  }
2584 
2585  auto &matcher = flag->GetMatcher();
2586  if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix)))
2587  {
2588  for (auto &flagName : matcher.GetFlagStrings())
2589  {
2590  if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix)))
2591  {
2592  break;
2593  }
2594  }
2595  }
2596  }
2597 
2598  if (optionType == OptionType::LongFlag && allowJoinedLongValue)
2599  {
2600  const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
2601  if (separator != chunk.npos)
2602  {
2603  std::string arg(chunk, 0, separator);
2604  if (auto flag = this->Match(arg.substr(longprefix.size())))
2605  {
2606  for (auto &choice : flag->HelpChoices(helpParams))
2607  {
2608  AddCompletionReply(chunk, arg + longseparator + choice);
2609  }
2610  }
2611  }
2612  } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
2613  {
2614  if (chunk.size() > shortprefix.size() + 1)
2615  {
2616  auto arg = chunk.at(shortprefix.size());
2617  //TODO: support -abcVALUE where a and b take no value
2618  if (auto flag = this->Match(arg))
2619  {
2620  for (auto &choice : flag->HelpChoices(helpParams))
2621  {
2622  AddCompletionReply(chunk, shortprefix + arg + choice);
2623  }
2624  }
2625  }
2626  }
2627  }
2628  }
2629 
2630 #ifndef ARGS_NOEXCEPT
2631  throw Completion(completion->Get());
2632 #else
2633  return true;
2634 #endif
2635  }
2636 
2637  template <typename It>
2638  It Parse(It begin, It end)
2639  {
2640  bool terminated = false;
2641  std::vector<Command *> commands = GetCommands();
2642 
2643  // Check all arg chunks
2644  for (auto it = begin; it != end; ++it)
2645  {
2646  if (Complete(it, end))
2647  {
2648  return end;
2649  }
2650 
2651  const auto &chunk = *it;
2652 
2653  if (!terminated && chunk == terminator)
2654  {
2655  terminated = true;
2656  } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag)
2657  {
2658  if (!ParseLong(it, end))
2659  {
2660  return it;
2661  }
2662  } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag)
2663  {
2664  if (!ParseShort(it, end))
2665  {
2666  return it;
2667  }
2668  } else if (!terminated && !commands.empty())
2669  {
2670  auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; });
2671  if (itCommand == commands.end())
2672  {
2673  const std::string errorMessage("Unknown command: " + chunk);
2674 #ifndef ARGS_NOEXCEPT
2675  throw ParseError(errorMessage);
2676 #else
2677  error = Error::Parse;
2678  errorMsg = errorMessage;
2679  return it;
2680 #endif
2681  }
2682 
2683  SelectCommand(*itCommand);
2684 
2685  if (const auto &coroutine = GetCoroutine())
2686  {
2687  ++it;
2688  RaiiSubparser coro(*this, std::vector<std::string>(it, end));
2689  coroutine(coro.Parser());
2690 #ifdef ARGS_NOEXCEPT
2691  error = GetError();
2692  if (error != Error::None)
2693  {
2694  return end;
2695  }
2696 
2697  if (!coro.Parser().IsParsed())
2698  {
2699  error = Error::Usage;
2700  return end;
2701  }
2702 #else
2703  if (!coro.Parser().IsParsed())
2704  {
2705  throw UsageError("Subparser::Parse was not called");
2706  }
2707 #endif
2708 
2709  break;
2710  }
2711 
2712  commands = GetCommands();
2713  } else
2714  {
2715  auto pos = GetNextPositional();
2716  if (pos)
2717  {
2718  pos->ParseValue(chunk);
2719 
2720  if (pos->KickOut())
2721  {
2722  return ++it;
2723  }
2724  } else
2725  {
2726  const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk);
2727 #ifndef ARGS_NOEXCEPT
2728  throw ParseError(errorMessage);
2729 #else
2730  error = Error::Parse;
2731  errorMsg = errorMessage;
2732  return it;
2733 #endif
2734  }
2735  }
2736 
2737  if (!readCompletion && completion != nullptr && completion->Matched())
2738  {
2739 #ifdef ARGS_NOEXCEPT
2740  error = Error::Completion;
2741 #endif
2742  readCompletion = true;
2743  ++it;
2744  const auto argsLeft = static_cast<size_t>(std::distance(it, end));
2745  if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft)
2746  {
2747 #ifndef ARGS_NOEXCEPT
2748  throw Completion("");
2749 #endif
2750  }
2751 
2752  std::vector<std::string> curArgs(++it, end);
2753  curArgs.resize(completion->cword);
2754 
2755  if (completion->syntax == "bash")
2756  {
2757  // bash tokenizes --flag=value as --flag=value
2758  for (size_t idx = 0; idx < curArgs.size(); )
2759  {
2760  if (idx > 0 && curArgs[idx] == "=")
2761  {
2762  curArgs[idx - 1] += "=";
2763  // Avoid warnings from -Wsign-conversion
2764  const auto signedIdx = static_cast<std::ptrdiff_t>(idx);
2765  if (idx + 1 < curArgs.size())
2766  {
2767  curArgs[idx - 1] += curArgs[idx + 1];
2768  curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2);
2769  } else
2770  {
2771  curArgs.erase(curArgs.begin() + signedIdx);
2772  }
2773  } else
2774  {
2775  ++idx;
2776  }
2777  }
2778 
2779  }
2780 #ifndef ARGS_NOEXCEPT
2781  try
2782  {
2783  Parse(curArgs.begin(), curArgs.end());
2784  throw Completion("");
2785  }
2786  catch (Completion &)
2787  {
2788  throw;
2789  }
2790  catch (args::Error&)
2791  {
2792  throw Completion("");
2793  }
2794 #else
2795  return Parse(curArgs.begin(), curArgs.end());
2796 #endif
2797  }
2798  }
2799 
2800  Validate(shortprefix, longprefix);
2801  return end;
2802  }
2803 
2804  public:
2805  HelpParams helpParams;
2806 
2807  ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string())
2808  {
2809  Description(description_);
2810  Epilog(epilog_);
2811  LongPrefix("--");
2812  ShortPrefix("-");
2813  LongSeparator("=");
2814  Terminator("--");
2815  SetArgumentSeparations(true, true, true, true);
2816  matched = true;
2817  }
2818 
2819  void AddCompletion(CompletionFlag &completionFlag)
2820  {
2821  completion = &completionFlag;
2822  Add(completionFlag);
2823  }
2824 
2827  const std::string &Prog() const
2828  { return helpParams.programName; }
2831  void Prog(const std::string &prog_)
2832  { this->helpParams.programName = prog_; }
2833 
2836  const std::string &LongPrefix() const
2837  { return longprefix; }
2840  void LongPrefix(const std::string &longprefix_)
2841  {
2842  this->longprefix = longprefix_;
2843  this->helpParams.longPrefix = longprefix_;
2844  }
2845 
2848  const std::string &ShortPrefix() const
2849  { return shortprefix; }
2852  void ShortPrefix(const std::string &shortprefix_)
2853  {
2854  this->shortprefix = shortprefix_;
2855  this->helpParams.shortPrefix = shortprefix_;
2856  }
2857 
2860  const std::string &LongSeparator() const
2861  { return longseparator; }
2864  void LongSeparator(const std::string &longseparator_)
2865  {
2866  if (longseparator_.empty())
2867  {
2868  const std::string errorMessage("longseparator can not be set to empty");
2869 #ifdef ARGS_NOEXCEPT
2870  error = Error::Usage;
2871  errorMsg = errorMessage;
2872 #else
2873  throw UsageError(errorMessage);
2874 #endif
2875  } else
2876  {
2877  this->longseparator = longseparator_;
2878  this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " ";
2879  }
2880  }
2881 
2884  const std::string &Terminator() const
2885  { return terminator; }
2888  void Terminator(const std::string &terminator_)
2889  { this->terminator = terminator_; }
2890 
2896  bool &allowJoinedShortValue_,
2897  bool &allowJoinedLongValue_,
2898  bool &allowSeparateShortValue_,
2899  bool &allowSeparateLongValue_) const
2900  {
2901  allowJoinedShortValue_ = this->allowJoinedShortValue;
2902  allowJoinedLongValue_ = this->allowJoinedLongValue;
2903  allowSeparateShortValue_ = this->allowSeparateShortValue;
2904  allowSeparateLongValue_ = this->allowSeparateLongValue;
2905  }
2906 
2915  const bool allowJoinedShortValue_,
2916  const bool allowJoinedLongValue_,
2917  const bool allowSeparateShortValue_,
2918  const bool allowSeparateLongValue_)
2919  {
2920  this->allowJoinedShortValue = allowJoinedShortValue_;
2921  this->allowJoinedLongValue = allowJoinedLongValue_;
2922  this->allowSeparateShortValue = allowSeparateShortValue_;
2923  this->allowSeparateLongValue = allowSeparateLongValue_;
2924 
2925  this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " ";
2926  this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " ";
2927  }
2928 
2931  void Help(std::ostream &help_) const
2932  {
2933  auto &command = SelectedCommand();
2934  const auto &commandDescription = command.Description().empty() ? command.Help() : command.Description();
2935  const auto description_text = Wrap(commandDescription, helpParams.width - helpParams.descriptionindent);
2936  const auto epilog_text = Wrap(command.Epilog(), helpParams.width - helpParams.descriptionindent);
2937 
2938  const bool hasoptions = command.HasFlag();
2939  const bool hasarguments = command.HasPositional();
2940 
2941  std::vector<std::string> prognameline;
2942  prognameline.push_back(helpParams.usageString);
2943  prognameline.push_back(Prog());
2944  auto commandProgLine = command.GetProgramLine(helpParams);
2945  prognameline.insert(prognameline.end(), commandProgLine.begin(), commandProgLine.end());
2946 
2947  const auto proglines = Wrap(prognameline.begin(), prognameline.end(),
2948  helpParams.width - (helpParams.progindent + helpParams.progtailindent),
2949  helpParams.width - helpParams.progindent);
2950  auto progit = std::begin(proglines);
2951  if (progit != std::end(proglines))
2952  {
2953  help_ << std::string(helpParams.progindent, ' ') << *progit << '\n';
2954  ++progit;
2955  }
2956  for (; progit != std::end(proglines); ++progit)
2957  {
2958  help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n';
2959  }
2960 
2961  help_ << '\n';
2962 
2963  if (!description_text.empty())
2964  {
2965  for (const auto &line: description_text)
2966  {
2967  help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
2968  }
2969  help_ << "\n";
2970  }
2971 
2972  bool lastDescriptionIsNewline = false;
2973 
2974  if (!helpParams.optionsString.empty())
2975  {
2976  help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n";
2977  }
2978 
2979  for (const auto &desc: command.GetDescription(helpParams, 0))
2980  {
2981  lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty();
2982  const auto groupindent = std::get<2>(desc) * helpParams.eachgroupindent;
2983  const auto flags = Wrap(std::get<0>(desc), helpParams.width - (helpParams.flagindent + helpParams.helpindent + helpParams.gutter));
2984  const auto info = Wrap(std::get<1>(desc), helpParams.width - (helpParams.helpindent + groupindent));
2985 
2986  std::string::size_type flagssize = 0;
2987  for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit)
2988  {
2989  if (flagsit != std::begin(flags))
2990  {
2991  help_ << '\n';
2992  }
2993  help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit;
2994  flagssize = Glyphs(*flagsit);
2995  }
2996 
2997  auto infoit = std::begin(info);
2998  // groupindent is on both sides of this inequality, and therefore can be removed
2999  if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription)
3000  {
3001  help_ << '\n';
3002  } else
3003  {
3004  // groupindent is on both sides of the minus sign, and therefore doesn't actually need to be in here
3005  help_ << std::string(helpParams.helpindent - (helpParams.flagindent + flagssize), ' ') << *infoit << '\n';
3006  ++infoit;
3007  }
3008  for (; infoit != std::end(info); ++infoit)
3009  {
3010  help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n';
3011  }
3012  }
3013  if (hasoptions && hasarguments && helpParams.showTerminator)
3014  {
3015  lastDescriptionIsNewline = false;
3016  for (const auto &item: Wrap(std::string("\"") + terminator + "\" can be used to terminate flag options and force all following arguments to be treated as positional options", helpParams.width - helpParams.flagindent))
3017  {
3018  help_ << std::string(helpParams.flagindent, ' ') << item << '\n';
3019  }
3020  }
3021 
3022  if (!lastDescriptionIsNewline)
3023  {
3024  help_ << "\n";
3025  }
3026 
3027  for (const auto &line: epilog_text)
3028  {
3029  help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
3030  }
3031  }
3032 
3037  std::string Help() const
3038  {
3039  std::ostringstream help_;
3040  Help(help_);
3041  return help_.str();
3042  }
3043 
3044  virtual void Reset() noexcept override
3045  {
3046  Command::Reset();
3047  matched = true;
3048  readCompletion = false;
3049  }
3050 
3057  template <typename It>
3058  It ParseArgs(It begin, It end)
3059  {
3060  // Reset all Matched statuses and errors
3061  Reset();
3062 #ifdef ARGS_NOEXCEPT
3063  error = GetError();
3064  if (error != Error::None)
3065  {
3066  return end;
3067  }
3068 #endif
3069  return Parse(begin, end);
3070  }
3071 
3077  template <typename T>
3078  auto ParseArgs(const T &args) -> decltype(std::begin(args))
3079  {
3080  return ParseArgs(std::begin(args), std::end(args));
3081  }
3082 
3089  bool ParseCLI(const int argc, const char * const * argv)
3090  {
3091  if (Prog().empty())
3092  {
3093  Prog(argv[0]);
3094  }
3095  const std::vector<std::string> args(argv + 1, argv + argc);
3096  return ParseArgs(args) == std::end(args);
3097  }
3098 
3099  template <typename T>
3100  bool ParseCLI(const T &args)
3101  {
3102  return ParseArgs(args) == std::end(args);
3103  }
3104  };
3105 
3106  inline Command::RaiiSubparser::RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_)
3107  : command(parser_.SelectedCommand()), parser(std::move(args_), parser_, command, parser_.helpParams), oldSubparser(command.subparser)
3108  {
3109  command.subparser = &parser;
3110  }
3111 
3112  inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams &params_): command(command_), parser(command, params_), oldSubparser(command.subparser)
3113  {
3114  command.subparser = &parser;
3115  }
3116 
3117  inline void Subparser::Parse()
3118  {
3119  isParsed = true;
3120  Reset();
3121  command.subparserDescription = GetDescription(helpParams, 0);
3122  command.subparserHasFlag = HasFlag();
3123  command.subparserHasPositional = HasPositional();
3124  command.subparserHasCommand = HasCommand();
3125  command.subparserProgramLine = GetProgramLine(helpParams);
3126  if (parser == nullptr)
3127  {
3128 #ifndef ARGS_NOEXCEPT
3129  throw args::SubparserError();
3130 #else
3131  error = Error::Subparser;
3132  return;
3133 #endif
3134  }
3135 
3136  auto it = parser->Parse(args.begin(), args.end());
3137  command.Validate(parser->ShortPrefix(), parser->LongPrefix());
3138  kicked.assign(it, args.end());
3139 
3140 #ifdef ARGS_NOEXCEPT
3141  command.subparserError = GetError();
3142 #endif
3143  }
3144 
3145  inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser)
3146  {
3147  parser.Help(os);
3148  return os;
3149  }
3150 
3153  class Flag : public FlagBase
3154  {
3155  public:
3156  Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_)
3157  {
3158  group_.Add(*this);
3159  }
3160 
3161  Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false): Flag(group_, name_, help_, std::move(matcher_), extraError_ ? Options::Single : Options::None)
3162  {
3163  }
3164 
3165  virtual ~Flag() {}
3166 
3169  bool Get() const
3170  {
3171  return Matched();
3172  }
3173 
3174  virtual Nargs NumberOfArguments() const noexcept override
3175  {
3176  return 0;
3177  }
3178 
3179  virtual void ParseValue(const std::vector<std::string>&) override
3180  {
3181  }
3182  };
3183 
3188  class HelpFlag : public Flag
3189  {
3190  public:
3191  HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {}
3192 
3193  virtual ~HelpFlag() {}
3194 
3195  virtual void ParseValue(const std::vector<std::string> &)
3196  {
3197 #ifdef ARGS_NOEXCEPT
3198  error = Error::Help;
3199  errorMsg = Name();
3200 #else
3201  throw Help(Name());
3202 #endif
3203  }
3204 
3207  bool Get() const noexcept
3208  {
3209  return Matched();
3210  }
3211  };
3212 
3215  class CounterFlag : public Flag
3216  {
3217  private:
3218  const int startcount;
3219  int count;
3220 
3221  public:
3222  CounterFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const int startcount_ = 0, Options options_ = {}):
3223  Flag(group_, name_, help_, std::move(matcher_), options_), startcount(startcount_), count(startcount_) {}
3224 
3225  virtual ~CounterFlag() {}
3226 
3227  virtual FlagBase *Match(const EitherFlag &arg) override
3228  {
3229  auto me = FlagBase::Match(arg);
3230  if (me)
3231  {
3232  ++count;
3233  }
3234  return me;
3235  }
3236 
3239  int &Get() noexcept
3240  {
3241  return count;
3242  }
3243 
3244  virtual void Reset() noexcept override
3245  {
3246  FlagBase::Reset();
3247  count = startcount;
3248  }
3249  };
3250 
3253  class ActionFlag : public FlagBase
3254  {
3255  private:
3256  std::function<void(const std::vector<std::string> &)> action;
3257  Nargs nargs;
3258 
3259  public:
3260  ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, std::function<void(const std::vector<std::string> &)> action_, Options options_ = {}):
3261  FlagBase(name_, help_, std::move(matcher_), options_), action(std::move(action_)), nargs(nargs_)
3262  {
3263  group_.Add(*this);
3264  }
3265 
3266  ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void(const std::string &)> action_, Options options_ = {}):
3267  FlagBase(name_, help_, std::move(matcher_), options_), nargs(1)
3268  {
3269  group_.Add(*this);
3270  action = [action_](const std::vector<std::string> &a) { return action_(a.at(0)); };
3271  }
3272 
3273  ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void()> action_, Options options_ = {}):
3274  FlagBase(name_, help_, std::move(matcher_), options_), nargs(0)
3275  {
3276  group_.Add(*this);
3277  action = [action_](const std::vector<std::string> &) { return action_(); };
3278  }
3279 
3280  virtual Nargs NumberOfArguments() const noexcept override
3281  { return nargs; }
3282 
3283  virtual void ParseValue(const std::vector<std::string> &value) override
3284  { action(value); }
3285  };
3286 
3294  {
3295  template <typename T>
3296  typename std::enable_if<!std::is_assignable<T, std::string>::value, bool>::type
3297  operator ()(const std::string &name, const std::string &value, T &destination)
3298  {
3299  std::istringstream ss(value);
3300  bool failed = !(ss >> destination);
3301 
3302  if (!failed)
3303  {
3304  ss >> std::ws;
3305  }
3306 
3307  if (ss.rdbuf()->in_avail() > 0 || failed)
3308  {
3309 #ifdef ARGS_NOEXCEPT
3310  (void)name;
3311  return false;
3312 #else
3313  std::ostringstream problem;
3314  problem << "Argument '" << name << "' received invalid value type '" << value << "'";
3315  throw ParseError(problem.str());
3316 #endif
3317  }
3318  return true;
3319  }
3320 
3321  template <typename T>
3322  typename std::enable_if<std::is_assignable<T, std::string>::value, bool>::type
3323  operator()(const std::string &, const std::string &value, T &destination)
3324  {
3325  destination = value;
3326  return true;
3327  }
3328  };
3329 
3335  template <
3336  typename T,
3337  typename Reader = ValueReader>
3338  class ValueFlag : public ValueFlagBase
3339  {
3340  protected:
3341  T value;
3342  T defaultValue;
3343 
3344  virtual std::string GetDefaultString(const HelpParams&) const override
3345  {
3346  return detail::ToString(defaultValue);
3347  }
3348 
3349  private:
3350  Reader reader;
3351 
3352  public:
3353 
3354  ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), value(defaultValue_), defaultValue(defaultValue_)
3355  {
3356  group_.Add(*this);
3357  }
3358 
3359  ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), const bool extraError_ = false): ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, extraError_ ? Options::Single : Options::None)
3360  {
3361  }
3362 
3363  ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): ValueFlag(group_, name_, help_, std::move(matcher_), T(), options_)
3364  {
3365  }
3366 
3367  virtual ~ValueFlag() {}
3368 
3369  virtual void ParseValue(const std::vector<std::string> &values_) override
3370  {
3371  const std::string &value_ = values_.at(0);
3372 
3373 #ifdef ARGS_NOEXCEPT
3374  if (!reader(name, value_, this->value))
3375  {
3376  error = Error::Parse;
3377  }
3378 #else
3379  reader(name, value_, this->value);
3380 #endif
3381  }
3382 
3383  virtual void Reset() noexcept override
3384  {
3385  ValueFlagBase::Reset();
3386  value = defaultValue;
3387  }
3388 
3391  T &Get() noexcept
3392  {
3393  return value;
3394  }
3395 
3398  const T &GetDefault() noexcept
3399  {
3400  return defaultValue;
3401  }
3402  };
3403 
3409  template <
3410  typename T,
3411  typename Reader = ValueReader>
3412  class ImplicitValueFlag : public ValueFlag<T, Reader>
3413  {
3414  protected:
3415  T implicitValue;
3416 
3417  public:
3418 
3419  ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {})
3420  : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_)
3421  {
3422  }
3423 
3424  ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {})
3425  : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_)
3426  {
3427  }
3428 
3429  ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_)
3430  : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue()
3431  {
3432  }
3433 
3434  virtual ~ImplicitValueFlag() {}
3435 
3436  virtual Nargs NumberOfArguments() const noexcept override
3437  {
3438  return {0, 1};
3439  }
3440 
3441  virtual void ParseValue(const std::vector<std::string> &value_) override
3442  {
3443  if (value_.empty())
3444  {
3445  this->value = implicitValue;
3446  } else
3447  {
3449  }
3450  }
3451  };
3452 
3459  template <
3460  typename T,
3461  template <typename...> class List = detail::vector,
3462  typename Reader = ValueReader>
3463  class NargsValueFlag : public FlagBase
3464  {
3465  protected:
3466 
3467  List<T> values;
3468  const List<T> defaultValues;
3469  Nargs nargs;
3470  Reader reader;
3471 
3472  public:
3473 
3474  typedef List<T> Container;
3475  typedef T value_type;
3476  typedef typename Container::allocator_type allocator_type;
3477  typedef typename Container::pointer pointer;
3478  typedef typename Container::const_pointer const_pointer;
3479  typedef T& reference;
3480  typedef const T& const_reference;
3481  typedef typename Container::size_type size_type;
3482  typedef typename Container::difference_type difference_type;
3483  typedef typename Container::iterator iterator;
3484  typedef typename Container::const_iterator const_iterator;
3485  typedef std::reverse_iterator<iterator> reverse_iterator;
3486  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3487 
3488  NargsValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, const List<T> &defaultValues_ = {}, Options options_ = {})
3489  : FlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_),nargs(nargs_)
3490  {
3491  group_.Add(*this);
3492  }
3493 
3494  virtual ~NargsValueFlag() {}
3495 
3496  virtual Nargs NumberOfArguments() const noexcept override
3497  {
3498  return nargs;
3499  }
3500 
3501  virtual void ParseValue(const std::vector<std::string> &values_) override
3502  {
3503  values.clear();
3504 
3505  for (const std::string &value : values_)
3506  {
3507  T v;
3508 #ifdef ARGS_NOEXCEPT
3509  if (!reader(name, value, v))
3510  {
3511  error = Error::Parse;
3512  }
3513 #else
3514  reader(name, value, v);
3515 #endif
3516  values.insert(std::end(values), v);
3517  }
3518  }
3519 
3520  List<T> &Get() noexcept
3521  {
3522  return values;
3523  }
3524 
3525  iterator begin() noexcept
3526  {
3527  return values.begin();
3528  }
3529 
3530  const_iterator begin() const noexcept
3531  {
3532  return values.begin();
3533  }
3534 
3535  const_iterator cbegin() const noexcept
3536  {
3537  return values.cbegin();
3538  }
3539 
3540  iterator end() noexcept
3541  {
3542  return values.end();
3543  }
3544 
3545  const_iterator end() const noexcept
3546  {
3547  return values.end();
3548  }
3549 
3550  const_iterator cend() const noexcept
3551  {
3552  return values.cend();
3553  }
3554 
3555  virtual void Reset() noexcept override
3556  {
3557  FlagBase::Reset();
3558  values = defaultValues;
3559  }
3560 
3561  virtual FlagBase *Match(const EitherFlag &arg) override
3562  {
3563  const bool wasMatched = Matched();
3564  auto me = FlagBase::Match(arg);
3565  if (me && !wasMatched)
3566  {
3567  values.clear();
3568  }
3569  return me;
3570  }
3571  };
3572 
3579  template <
3580  typename T,
3581  template <typename...> class List = detail::vector,
3582  typename Reader = ValueReader>
3584  {
3585  private:
3586  using Container = List<T>;
3587  Container values;
3588  const Container defaultValues;
3589  Reader reader;
3590 
3591  public:
3592 
3593  typedef T value_type;
3594  typedef typename Container::allocator_type allocator_type;
3595  typedef typename Container::pointer pointer;
3596  typedef typename Container::const_pointer const_pointer;
3597  typedef T& reference;
3598  typedef const T& const_reference;
3599  typedef typename Container::size_type size_type;
3600  typedef typename Container::difference_type difference_type;
3601  typedef typename Container::iterator iterator;
3602  typedef typename Container::const_iterator const_iterator;
3603  typedef std::reverse_iterator<iterator> reverse_iterator;
3604  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3605 
3606  ValueFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Container &defaultValues_ = Container(), Options options_ = {}):
3607  ValueFlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_)
3608  {
3609  group_.Add(*this);
3610  }
3611 
3612  virtual ~ValueFlagList() {}
3613 
3614  virtual void ParseValue(const std::vector<std::string> &values_) override
3615  {
3616  const std::string &value_ = values_.at(0);
3617 
3618  T v;
3619 #ifdef ARGS_NOEXCEPT
3620  if (!reader(name, value_, v))
3621  {
3622  error = Error::Parse;
3623  }
3624 #else
3625  reader(name, value_, v);
3626 #endif
3627  values.insert(std::end(values), v);
3628  }
3629 
3632  Container &Get() noexcept
3633  {
3634  return values;
3635  }
3636 
3637  virtual std::string Name() const override
3638  {
3639  return name + std::string("...");
3640  }
3641 
3642  virtual void Reset() noexcept override
3643  {
3644  ValueFlagBase::Reset();
3645  values = defaultValues;
3646  }
3647 
3648  virtual FlagBase *Match(const EitherFlag &arg) override
3649  {
3650  const bool wasMatched = Matched();
3651  auto me = FlagBase::Match(arg);
3652  if (me && !wasMatched)
3653  {
3654  values.clear();
3655  }
3656  return me;
3657  }
3658 
3659  iterator begin() noexcept
3660  {
3661  return values.begin();
3662  }
3663 
3664  const_iterator begin() const noexcept
3665  {
3666  return values.begin();
3667  }
3668 
3669  const_iterator cbegin() const noexcept
3670  {
3671  return values.cbegin();
3672  }
3673 
3674  iterator end() noexcept
3675  {
3676  return values.end();
3677  }
3678 
3679  const_iterator end() const noexcept
3680  {
3681  return values.end();
3682  }
3683 
3684  const_iterator cend() const noexcept
3685  {
3686  return values.cend();
3687  }
3688  };
3689 
3697  template <
3698  typename K,
3699  typename T,
3700  typename Reader = ValueReader,
3701  template <typename...> class Map = detail::unordered_map>
3702  class MapFlag : public ValueFlagBase
3703  {
3704  private:
3705  const Map<K, T> map;
3706  T value;
3707  const T defaultValue;
3708  Reader reader;
3709 
3710  protected:
3711  virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3712  {
3713  return detail::MapKeysToStrings(map);
3714  }
3715 
3716  public:
3717 
3718  MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map<K, T> &map_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), map(map_), value(defaultValue_), defaultValue(defaultValue_)
3719  {
3720  group_.Add(*this);
3721  }
3722 
3723  MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map<K, T> &map_, const T &defaultValue_ = T(), const bool extraError_ = false): MapFlag(group_, name_, help_, std::move(matcher_), map_, defaultValue_, extraError_ ? Options::Single : Options::None)
3724  {
3725  }
3726 
3727  MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map<K, T> &map_, Options options_): MapFlag(group_, name_, help_, std::move(matcher_), map_, T(), options_)
3728  {
3729  }
3730 
3731  virtual ~MapFlag() {}
3732 
3733  virtual void ParseValue(const std::vector<std::string> &values_) override
3734  {
3735  const std::string &value_ = values_.at(0);
3736 
3737  K key;
3738 #ifdef ARGS_NOEXCEPT
3739  if (!reader(name, value_, key))
3740  {
3741  error = Error::Parse;
3742  }
3743 #else
3744  reader(name, value_, key);
3745 #endif
3746  auto it = map.find(key);
3747  if (it == std::end(map))
3748  {
3749  std::ostringstream problem;
3750  problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3751 #ifdef ARGS_NOEXCEPT
3752  error = Error::Map;
3753  errorMsg = problem.str();
3754 #else
3755  throw MapError(problem.str());
3756 #endif
3757  } else
3758  {
3759  this->value = it->second;
3760  }
3761  }
3762 
3765  T &Get() noexcept
3766  {
3767  return value;
3768  }
3769 
3770  virtual void Reset() noexcept override
3771  {
3772  ValueFlagBase::Reset();
3773  value = defaultValue;
3774  }
3775  };
3776 
3785  template <
3786  typename K,
3787  typename T,
3788  template <typename...> class List = detail::vector,
3789  typename Reader = ValueReader,
3790  template <typename...> class Map = detail::unordered_map>
3792  {
3793  private:
3794  using Container = List<T>;
3795  const Map<K, T> map;
3796  Container values;
3797  const Container defaultValues;
3798  Reader reader;
3799 
3800  protected:
3801  virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3802  {
3803  return detail::MapKeysToStrings(map);
3804  }
3805 
3806  public:
3807  typedef T value_type;
3808  typedef typename Container::allocator_type allocator_type;
3809  typedef typename Container::pointer pointer;
3810  typedef typename Container::const_pointer const_pointer;
3811  typedef T& reference;
3812  typedef const T& const_reference;
3813  typedef typename Container::size_type size_type;
3814  typedef typename Container::difference_type difference_type;
3815  typedef typename Container::iterator iterator;
3816  typedef typename Container::const_iterator const_iterator;
3817  typedef std::reverse_iterator<iterator> reverse_iterator;
3818  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3819 
3820  MapFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map<K, T> &map_, const Container &defaultValues_ = Container()): ValueFlagBase(name_, help_, std::move(matcher_)), map(map_), values(defaultValues_), defaultValues(defaultValues_)
3821  {
3822  group_.Add(*this);
3823  }
3824 
3825  virtual ~MapFlagList() {}
3826 
3827  virtual void ParseValue(const std::vector<std::string> &values_) override
3828  {
3829  const std::string &value = values_.at(0);
3830 
3831  K key;
3832 #ifdef ARGS_NOEXCEPT
3833  if (!reader(name, value, key))
3834  {
3835  error = Error::Parse;
3836  }
3837 #else
3838  reader(name, value, key);
3839 #endif
3840  auto it = map.find(key);
3841  if (it == std::end(map))
3842  {
3843  std::ostringstream problem;
3844  problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3845 #ifdef ARGS_NOEXCEPT
3846  error = Error::Map;
3847  errorMsg = problem.str();
3848 #else
3849  throw MapError(problem.str());
3850 #endif
3851  } else
3852  {
3853  this->values.emplace_back(it->second);
3854  }
3855  }
3856 
3859  Container &Get() noexcept
3860  {
3861  return values;
3862  }
3863 
3864  virtual std::string Name() const override
3865  {
3866  return name + std::string("...");
3867  }
3868 
3869  virtual void Reset() noexcept override
3870  {
3871  ValueFlagBase::Reset();
3872  values = defaultValues;
3873  }
3874 
3875  virtual FlagBase *Match(const EitherFlag &arg) override
3876  {
3877  const bool wasMatched = Matched();
3878  auto me = FlagBase::Match(arg);
3879  if (me && !wasMatched)
3880  {
3881  values.clear();
3882  }
3883  return me;
3884  }
3885 
3886  iterator begin() noexcept
3887  {
3888  return values.begin();
3889  }
3890 
3891  const_iterator begin() const noexcept
3892  {
3893  return values.begin();
3894  }
3895 
3896  const_iterator cbegin() const noexcept
3897  {
3898  return values.cbegin();
3899  }
3900 
3901  iterator end() noexcept
3902  {
3903  return values.end();
3904  }
3905 
3906  const_iterator end() const noexcept
3907  {
3908  return values.end();
3909  }
3910 
3911  const_iterator cend() const noexcept
3912  {
3913  return values.cend();
3914  }
3915  };
3916 
3922  template <
3923  typename T,
3924  typename Reader = ValueReader>
3926  {
3927  private:
3928  T value;
3929  const T defaultValue;
3930  Reader reader;
3931  public:
3932  Positional(Group &group_, const std::string &name_, const std::string &help_, const T &defaultValue_ = T(), Options options_ = {}): PositionalBase(name_, help_, options_), value(defaultValue_), defaultValue(defaultValue_)
3933  {
3934  group_.Add(*this);
3935  }
3936 
3937  Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_)
3938  {
3939  }
3940 
3941  virtual ~Positional() {}
3942 
3943  virtual void ParseValue(const std::string &value_) override
3944  {
3945 #ifdef ARGS_NOEXCEPT
3946  if (!reader(name, value_, this->value))
3947  {
3948  error = Error::Parse;
3949  }
3950 #else
3951  reader(name, value_, this->value);
3952 #endif
3953  ready = false;
3954  matched = true;
3955  }
3956 
3959  T &Get() noexcept
3960  {
3961  return value;
3962  }
3963 
3964  virtual void Reset() noexcept override
3965  {
3966  PositionalBase::Reset();
3967  value = defaultValue;
3968  }
3969  };
3970 
3977  template <
3978  typename T,
3979  template <typename...> class List = detail::vector,
3980  typename Reader = ValueReader>
3982  {
3983  private:
3984  using Container = List<T>;
3985  Container values;
3986  const Container defaultValues;
3987  Reader reader;
3988 
3989  public:
3990  typedef T value_type;
3991  typedef typename Container::allocator_type allocator_type;
3992  typedef typename Container::pointer pointer;
3993  typedef typename Container::const_pointer const_pointer;
3994  typedef T& reference;
3995  typedef const T& const_reference;
3996  typedef typename Container::size_type size_type;
3997  typedef typename Container::difference_type difference_type;
3998  typedef typename Container::iterator iterator;
3999  typedef typename Container::const_iterator const_iterator;
4000  typedef std::reverse_iterator<iterator> reverse_iterator;
4001  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4002 
4003  PositionalList(Group &group_, const std::string &name_, const std::string &help_, const Container &defaultValues_ = Container(), Options options_ = {}): PositionalBase(name_, help_, options_), values(defaultValues_), defaultValues(defaultValues_)
4004  {
4005  group_.Add(*this);
4006  }
4007 
4008  PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_)
4009  {
4010  }
4011 
4012  virtual ~PositionalList() {}
4013 
4014  virtual void ParseValue(const std::string &value_) override
4015  {
4016  T v;
4017 #ifdef ARGS_NOEXCEPT
4018  if (!reader(name, value_, v))
4019  {
4020  error = Error::Parse;
4021  }
4022 #else
4023  reader(name, value_, v);
4024 #endif
4025  values.insert(std::end(values), v);
4026  matched = true;
4027  }
4028 
4029  virtual std::string Name() const override
4030  {
4031  return name + std::string("...");
4032  }
4033 
4036  Container &Get() noexcept
4037  {
4038  return values;
4039  }
4040 
4041  virtual void Reset() noexcept override
4042  {
4043  PositionalBase::Reset();
4044  values = defaultValues;
4045  }
4046 
4047  virtual PositionalBase *GetNextPositional() override
4048  {
4049  const bool wasMatched = Matched();
4050  auto me = PositionalBase::GetNextPositional();
4051  if (me && !wasMatched)
4052  {
4053  values.clear();
4054  }
4055  return me;
4056  }
4057 
4058  iterator begin() noexcept
4059  {
4060  return values.begin();
4061  }
4062 
4063  const_iterator begin() const noexcept
4064  {
4065  return values.begin();
4066  }
4067 
4068  const_iterator cbegin() const noexcept
4069  {
4070  return values.cbegin();
4071  }
4072 
4073  iterator end() noexcept
4074  {
4075  return values.end();
4076  }
4077 
4078  const_iterator end() const noexcept
4079  {
4080  return values.end();
4081  }
4082 
4083  const_iterator cend() const noexcept
4084  {
4085  return values.cend();
4086  }
4087  };
4088 
4096  template <
4097  typename K,
4098  typename T,
4099  typename Reader = ValueReader,
4100  template <typename...> class Map = detail::unordered_map>
4102  {
4103  private:
4104  const Map<K, T> map;
4105  T value;
4106  const T defaultValue;
4107  Reader reader;
4108 
4109  protected:
4110  virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4111  {
4112  return detail::MapKeysToStrings(map);
4113  }
4114 
4115  public:
4116 
4117  MapPositional(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const T &defaultValue_ = T(), Options options_ = {}):
4118  PositionalBase(name_, help_, options_), map(map_), value(defaultValue_), defaultValue(defaultValue_)
4119  {
4120  group_.Add(*this);
4121  }
4122 
4123  virtual ~MapPositional() {}
4124 
4125  virtual void ParseValue(const std::string &value_) override
4126  {
4127  K key;
4128 #ifdef ARGS_NOEXCEPT
4129  if (!reader(name, value_, key))
4130  {
4131  error = Error::Parse;
4132  }
4133 #else
4134  reader(name, value_, key);
4135 #endif
4136  auto it = map.find(key);
4137  if (it == std::end(map))
4138  {
4139  std::ostringstream problem;
4140  problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4141 #ifdef ARGS_NOEXCEPT
4142  error = Error::Map;
4143  errorMsg = problem.str();
4144 #else
4145  throw MapError(problem.str());
4146 #endif
4147  } else
4148  {
4149  this->value = it->second;
4150  ready = false;
4151  matched = true;
4152  }
4153  }
4154 
4157  T &Get() noexcept
4158  {
4159  return value;
4160  }
4161 
4162  virtual void Reset() noexcept override
4163  {
4164  PositionalBase::Reset();
4165  value = defaultValue;
4166  }
4167  };
4168 
4177  template <
4178  typename K,
4179  typename T,
4180  template <typename...> class List = detail::vector,
4181  typename Reader = ValueReader,
4182  template <typename...> class Map = detail::unordered_map>
4184  {
4185  private:
4186  using Container = List<T>;
4187 
4188  const Map<K, T> map;
4189  Container values;
4190  const Container defaultValues;
4191  Reader reader;
4192 
4193  protected:
4194  virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4195  {
4196  return detail::MapKeysToStrings(map);
4197  }
4198 
4199  public:
4200  typedef T value_type;
4201  typedef typename Container::allocator_type allocator_type;
4202  typedef typename Container::pointer pointer;
4203  typedef typename Container::const_pointer const_pointer;
4204  typedef T& reference;
4205  typedef const T& const_reference;
4206  typedef typename Container::size_type size_type;
4207  typedef typename Container::difference_type difference_type;
4208  typedef typename Container::iterator iterator;
4209  typedef typename Container::const_iterator const_iterator;
4210  typedef std::reverse_iterator<iterator> reverse_iterator;
4211  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4212 
4213  MapPositionalList(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const Container &defaultValues_ = Container(), Options options_ = {}):
4214  PositionalBase(name_, help_, options_), map(map_), values(defaultValues_), defaultValues(defaultValues_)
4215  {
4216  group_.Add(*this);
4217  }
4218 
4219  virtual ~MapPositionalList() {}
4220 
4221  virtual void ParseValue(const std::string &value_) override
4222  {
4223  K key;
4224 #ifdef ARGS_NOEXCEPT
4225  if (!reader(name, value_, key))
4226  {
4227  error = Error::Parse;
4228  }
4229 #else
4230  reader(name, value_, key);
4231 #endif
4232  auto it = map.find(key);
4233  if (it == std::end(map))
4234  {
4235  std::ostringstream problem;
4236  problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4237 #ifdef ARGS_NOEXCEPT
4238  error = Error::Map;
4239  errorMsg = problem.str();
4240 #else
4241  throw MapError(problem.str());
4242 #endif
4243  } else
4244  {
4245  this->values.emplace_back(it->second);
4246  matched = true;
4247  }
4248  }
4249 
4252  Container &Get() noexcept
4253  {
4254  return values;
4255  }
4256 
4257  virtual std::string Name() const override
4258  {
4259  return name + std::string("...");
4260  }
4261 
4262  virtual void Reset() noexcept override
4263  {
4264  PositionalBase::Reset();
4265  values = defaultValues;
4266  }
4267 
4268  virtual PositionalBase *GetNextPositional() override
4269  {
4270  const bool wasMatched = Matched();
4271  auto me = PositionalBase::GetNextPositional();
4272  if (me && !wasMatched)
4273  {
4274  values.clear();
4275  }
4276  return me;
4277  }
4278 
4279  iterator begin() noexcept
4280  {
4281  return values.begin();
4282  }
4283 
4284  const_iterator begin() const noexcept
4285  {
4286  return values.begin();
4287  }
4288 
4289  const_iterator cbegin() const noexcept
4290  {
4291  return values.cbegin();
4292  }
4293 
4294  iterator end() noexcept
4295  {
4296  return values.end();
4297  }
4298 
4299  const_iterator end() const noexcept
4300  {
4301  return values.end();
4302  }
4303 
4304  const_iterator cend() const noexcept
4305  {
4306  return values.cend();
4307  }
4308  };
4309 }
4310 
4311 #endif
A flag class that calls a function when it's matched.
Definition: args.hxx:3254
virtual Nargs NumberOfArguments() const noexcept override
Defines how many values can be consumed by this option.
Definition: args.hxx:3280
virtual void ParseValue(const std::vector< std::string > &value) override
Parse values of this option.
Definition: args.hxx:3283
The main user facing command line argument parser class.
Definition: args.hxx:2248
void SetArgumentSeparations(const bool allowJoinedShortValue_, const bool allowJoinedLongValue_, const bool allowSeparateShortValue_, const bool allowSeparateLongValue_)
Change allowed option separation.
Definition: args.hxx:2914
void Prog(const std::string &prog_)
The program name for help generation.
Definition: args.hxx:2831
const std::string & LongPrefix() const
The prefix for long flags.
Definition: args.hxx:2836
It ParseArgs(It begin, It end)
Parse all arguments.
Definition: args.hxx:3058
void LongPrefix(const std::string &longprefix_)
The prefix for long flags.
Definition: args.hxx:2840
void LongSeparator(const std::string &longseparator_)
The separator for long flags.
Definition: args.hxx:2864
void Help(std::ostream &help_) const
Pass the help menu into an ostream.
Definition: args.hxx:2931
const std::string & LongSeparator() const
The separator for long flags.
Definition: args.hxx:2860
bool ParseCLI(const int argc, const char *const *argv)
Convenience function to parse the CLI from argc and argv.
Definition: args.hxx:3089
auto ParseArgs(const T &args) -> decltype(std::begin(args))
Parse all arguments.
Definition: args.hxx:3078
void Terminator(const std::string &terminator_)
The terminator that forcibly separates flags from positionals.
Definition: args.hxx:2888
void GetArgumentSeparations(bool &allowJoinedShortValue_, bool &allowJoinedLongValue_, bool &allowSeparateShortValue_, bool &allowSeparateLongValue_) const
Get the current argument separation parameters.
Definition: args.hxx:2895
const std::string & Prog() const
The program name for help generation.
Definition: args.hxx:2827
std::string Help() const
Generate a help menu as a string.
Definition: args.hxx:3037
void ShortPrefix(const std::string &shortprefix_)
The prefix for short flags.
Definition: args.hxx:2852
const std::string & Terminator() const
The terminator that forcibly separates flags from positionals.
Definition: args.hxx:2884
std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end, const bool allowSeparate, const bool allowJoined, const bool hasJoined, const std::string &joinedArg, const bool canDiscardJoined, std::vector< std::string > &values)
(INTERNAL) Parse flag's values
Definition: args.hxx:2322
const std::string & ShortPrefix() const
The prefix for short flags.
Definition: args.hxx:2848
Base class for all match types.
Definition: args.hxx:794
void KickOut(bool kickout_) noexcept
Sets a kick-out value for building subparsers.
Definition: args.hxx:889
bool KickOut() const noexcept
Gets the kick-out value for building subparsers.
Definition: args.hxx:902
Main class for building subparsers.
Definition: args.hxx:1712
const std::string & Description() const
The description that appears above options.
Definition: args.hxx:1827
virtual PositionalBase * GetNextPositional() override
Get the next ready positional, or nullptr if there is none.
Definition: args.hxx:1948
const std::string & Help() const
The description of command.
Definition: args.hxx:1852
const std::string & ProglinePostfix() const
The description that appears on the prog line after options.
Definition: args.hxx:1817
virtual std::vector< std::string > GetProgramLine(const HelpParams &params) const override
Get the names of positional parameters.
Definition: args.hxx:2049
void Description(const std::string &description_)
The description that appears above options.
Definition: args.hxx:1832
virtual bool HasPositional() const override
Get whether this has any PositionalBase children.
Definition: args.hxx:1984
void Epilog(const std::string &epilog_)
The description that appears below options.
Definition: args.hxx:1842
void ProglinePostfix(const std::string &proglinePostfix_)
The description that appears on the prog line after options.
Definition: args.hxx:1822
const std::string & Epilog() const
The description that appears below options.
Definition: args.hxx:1837
const std::string & Name() const
The name of command.
Definition: args.hxx:1847
virtual bool HasCommand() const override
Get whether this has any Command children.
Definition: args.hxx:1989
virtual bool HasFlag() const override
Get whether this has any FlagBase children.
Definition: args.hxx:1979
virtual FlagBase * Match(const EitherFlag &flag) override
Return the first FlagBase that matches flag, or nullptr.
Definition: args.hxx:1884
virtual bool Matched() const noexcept override
Whether or not this group matches validation.
Definition: args.hxx:1865
void RequireCommand(bool value)
If value is true, parser will fail if no command was parsed.
Definition: args.hxx:1859
virtual std::vector< std::tuple< std::string, std::string, unsigned > > GetDescription(const HelpParams &params, const unsigned int indent) const override
Get all the child descriptions for help generation.
Definition: args.hxx:2074
Definition: args.hxx:1238
virtual Nargs NumberOfArguments() const noexcept override
Defines how many values can be consumed by this option.
Definition: args.hxx:1252
std::string Get() noexcept
Get the completion reply.
Definition: args.hxx:1265
virtual void ParseValue(const std::vector< std::string > &value_) override
Parse values of this option.
Definition: args.hxx:1257
An exception that contains autocompletion reply.
Definition: args.hxx:343
A flag class that simply counts the number of times it's matched.
Definition: args.hxx:3216
int & Get() noexcept
Get the count.
Definition: args.hxx:3239
Base error class.
Definition: args.hxx:262
Error that occurs when a singular flag is specified multiple times.
Definition: args.hxx:316
Base class for all flag options.
Definition: args.hxx:1081
virtual void ParseValue(const std::vector< std::string > &value)=0
Parse values of this option.
virtual Nargs NumberOfArguments() const noexcept=0
Defines how many values can be consumed by this option.
Boolean argument matcher.
Definition: args.hxx:3154
virtual Nargs NumberOfArguments() const noexcept override
Defines how many values can be consumed by this option.
Definition: args.hxx:3174
virtual void ParseValue(const std::vector< std::string > &) override
Parse values of this option.
Definition: args.hxx:3179
bool Get() const
Get whether this was matched.
Definition: args.hxx:3169
Class for using global options in ArgumentParser.
Definition: args.hxx:1631
Class for all kinds of validating groups, including ArgumentParser.
Definition: args.hxx:1343
virtual bool HasCommand() const override
Get whether this has any Command children.
Definition: args.hxx:1497
virtual FlagBase * Match(const EitherFlag &flag) override
Return the first FlagBase that matches flag, or nullptr.
Definition: args.hxx:1428
virtual bool HasPositional() const override
Get whether this has any PositionalBase children.
Definition: args.hxx:1488
Group(Group &group_, const std::string &help_=std::string(), const std::function< bool(const Group &)> &validator_=Validators::DontCare, Options options_={})
If help is empty, this group will not be printed in help output.
Definition: args.hxx:1403
virtual std::vector< std::tuple< std::string, std::string, unsigned > > GetDescription(const HelpParams &params, const unsigned int indent) const override
Get all the child descriptions for help generation.
Definition: args.hxx:1527
std::vector< Base * >::size_type MatchedChildren() const
Count the number of matched children this group has.
Definition: args.hxx:1504
virtual bool HasFlag() const override
Get whether this has any FlagBase children.
Definition: args.hxx:1479
Group(const std::string &help_=std::string(), const std::function< bool(const Group &)> &validator_=Validators::DontCare, Options options_={})
If help is empty, this group will not be printed in help output.
Definition: args.hxx:1401
virtual bool Matched() const noexcept override
Whether or not this group matches validation.
Definition: args.hxx:1513
virtual std::vector< std::string > GetProgramLine(const HelpParams &params) const override
Get the names of positional parameters.
Definition: args.hxx:1557
const std::vector< Base * > & Children() const
Get all this group's children.
Definition: args.hxx:1418
bool Get() const
Get validation.
Definition: args.hxx:1520
virtual PositionalBase * GetNextPositional() override
Get the next ready positional, or nullptr if there is none.
Definition: args.hxx:1463
void Add(Base &child)
Append a child to this Group.
Definition: args.hxx:1411
Help flag class.
Definition: args.hxx:3189
bool Get() const noexcept
Get whether this was matched.
Definition: args.hxx:3207
virtual void ParseValue(const std::vector< std::string > &)
Parse values of this option.
Definition: args.hxx:3195
An exception that indicates that the user has requested help.
Definition: args.hxx:325
An optional argument-accepting flag class.
Definition: args.hxx:3413
virtual void ParseValue(const std::vector< std::string > &value_) override
Parse values of this option.
Definition: args.hxx:3441
virtual Nargs NumberOfArguments() const noexcept override
Defines how many values can be consumed by this option.
Definition: args.hxx:3436
Errors in map lookups.
Definition: args.hxx:307
A mapping value flag list class.
Definition: args.hxx:3792
Container & Get() noexcept
Get the value.
Definition: args.hxx:3859
virtual void ParseValue(const std::vector< std::string > &values_) override
Parse values of this option.
Definition: args.hxx:3827
A mapping value flag class.
Definition: args.hxx:3703
virtual void ParseValue(const std::vector< std::string > &values_) override
Parse values of this option.
Definition: args.hxx:3733
T & Get() noexcept
Get the value.
Definition: args.hxx:3765
A positional argument mapping list class.
Definition: args.hxx:4184
Container & Get() noexcept
Get the value.
Definition: args.hxx:4252
A positional argument mapping class.
Definition: args.hxx:4102
T & Get() noexcept
Get the value.
Definition: args.hxx:4157
A class of "matchers", specifying short and flags that can possibly be matched.
Definition: args.hxx:411
std::vector< EitherFlag > GetFlagStrings() const
(INTERNAL) Get all flag strings as a vector, with the prefixes embedded
Definition: args.hxx:494
EitherFlag GetShortOrAny() const
(INTERNAL) Get short flag if it exists or any long flag
Definition: args.hxx:529
Matcher(Short &&shortIn, Long &&longIn)
Specify short and long flags separately as iterables.
Definition: args.hxx:447
Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd)
Specify short and long flags separately as iterators.
Definition: args.hxx:422
bool Match(const std::string &flag) const
(INTERNAL) Check if there is a match of a long flag
Definition: args.hxx:480
EitherFlag GetLongOrAny() const
(INTERNAL) Get long flag if it exists or any short flag
Definition: args.hxx:511
bool Match(const char flag) const
(INTERNAL) Check if there is a match of a short flag
Definition: args.hxx:473
bool Match(const EitherFlag &flag) const
(INTERNAL) Check if there is a match of a flag
Definition: args.hxx:487
Matcher(std::initializer_list< EitherFlag > in)
Specify a mixed single initializer-list of both short and long flags.
Definition: args.hxx:463
Base class for all match types that have a name.
Definition: args.hxx:934
void HelpDefault(const std::string &str)
Sets default value string that will be added to argument description.
Definition: args.hxx:970
void HelpChoices(const std::vector< std::string > &array)
Sets choices strings that will be added to argument description.
Definition: args.hxx:986
std::string HelpDefault(const HelpParams &params) const
Gets default value string that will be added to argument description.
Definition: args.hxx:978
std::vector< std::string > HelpChoices(const HelpParams &params) const
Gets choices strings that will be added to argument description.
Definition: args.hxx:994
A variadic arguments accepting flag class.
Definition: args.hxx:3464
virtual Nargs NumberOfArguments() const noexcept override
Defines how many values can be consumed by this option.
Definition: args.hxx:3496
virtual void ParseValue(const std::vector< std::string > &values_) override
Parse values of this option.
Definition: args.hxx:3501
Errors that occur during regular parsing.
Definition: args.hxx:280
Base class for positional options.
Definition: args.hxx:1283
A positional argument class that pushes the found values into a list.
Definition: args.hxx:3982
Container & Get() noexcept
Get the values.
Definition: args.hxx:4036
A positional argument class.
Definition: args.hxx:3926
T & Get() noexcept
Get the value.
Definition: args.hxx:3959
Errors that when a required flag is omitted.
Definition: args.hxx:298
Utility class for building subparsers with coroutines/callbacks.
Definition: args.hxx:1657
void Parse()
Continue parsing arguments for new command.
Definition: args.hxx:3117
const std::vector< std::string > & KickedOut() const noexcept
Returns a vector of kicked out arguments.
Definition: args.hxx:1701
bool IsParsed() const
(INTERNAL) Determines whether Parse was called or not.
Definition: args.hxx:1688
Errors that occur during usage.
Definition: args.hxx:271
Errors that are detected from group validation after parsing finishes.
Definition: args.hxx:289
Base class for value-accepting flag options.
Definition: args.hxx:1225
virtual Nargs NumberOfArguments() const noexcept override
Defines how many values can be consumed by this option.
Definition: args.hxx:1231
An argument-accepting flag class that pushes the found values into a list.
Definition: args.hxx:3584
Container & Get() noexcept
Get the values.
Definition: args.hxx:3632
virtual void ParseValue(const std::vector< std::string > &values_) override
Parse values of this option.
Definition: args.hxx:3614
An argument-accepting flag class.
Definition: args.hxx:3339
T & Get() noexcept
Get the value.
Definition: args.hxx:3391
const T & GetDefault() noexcept
Get the default value.
Definition: args.hxx:3398
virtual void ParseValue(const std::vector< std::string > &values_) override
Parse values of this option.
Definition: args.hxx:3369
Definition: args.hxx:1029
contains all the functionality of the args library
Options
Attributes for flags.
Definition: args.hxx:549
@ HiddenFromCompletion
Flag is excluded from auto completion.
@ Global
Flag is global and can be used in any subcommand.
@ Single
Flag can't be passed multiple times.
@ None
Default options.
@ HiddenFromUsage
Flag is excluded from usage line.
@ Hidden
Flag is excluded from options help and usage line.
@ Required
Flag can't be omitted.
@ KickOut
Flag stops a parser.
@ HiddenFromDescription
Flag is excluded from options help.
auto get(Option &option_) -> decltype(option_.Get())
Getter to grab the value from the argument type.
Definition: args.hxx:76
std::string::size_type Glyphs(const std::string &string_)
(INTERNAL) Count UTF-8 glyphs
Definition: args.hxx:89
std::vector< std::string > Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth=0)
(INTERNAL) Wrap a string into a vector of lines
Definition: args.hxx:212
A simple unified option type for unified initializer lists for the Matcher class.
Definition: args.hxx:353
static std::unordered_set< std::string > GetLong(std::initializer_list< EitherFlag > flags)
Get just the long flags from an initializer list of EitherFlags.
Definition: args.hxx:363
static std::unordered_set< char > GetShort(std::initializer_list< EitherFlag > flags)
Get just the short flags from an initializer list of EitherFlags.
Definition: args.hxx:378
Default validators.
Definition: args.hxx:1352
A simple structure of parameters for easy user-modifyable help menus.
Definition: args.hxx:605
std::string programName
The program name for help generation.
Definition: args.hxx:662
bool showCommandFullHelp
Show command's descriptions and epilog.
Definition: args.hxx:670
bool proglineShowFlags
Show flags in program line.
Definition: args.hxx:706
std::string usageString
Program line prefix.
Definition: args.hxx:714
std::string proglineNonrequiredClose
The postfix for progline non-required argument.
Definition: args.hxx:702
bool proglinePreferShortFlags
Use short flags in program lines when possible.
Definition: args.hxx:710
std::string proglineCommand
The prefix for progline when command has any subcommands.
Definition: args.hxx:678
std::string proglineOptions
The postfix for progline when showProglineOptions is true and command has any flags.
Definition: args.hxx:674
std::string longSeparator
The separator for long flags.
Definition: args.hxx:658
bool showValueName
Show value name.
Definition: args.hxx:726
std::string proglineValueOpen
The prefix for progline value.
Definition: args.hxx:682
std::string valueOpen
The prefix for option value.
Definition: args.hxx:734
std::string proglineNonrequiredOpen
The prefix for progline non-required argument.
Definition: args.hxx:698
bool showCommandChildren
Show command's flags.
Definition: args.hxx:666
bool showProglineOptions
Show the {OPTIONS} on the prog line when this is true.
Definition: args.hxx:638
std::string valueClose
The postfix for option value.
Definition: args.hxx:738
std::string longPrefix
The prefix for long flags.
Definition: args.hxx:650
std::string proglineRequiredClose
The postfix for progline required argument.
Definition: args.hxx:694
std::string shortPrefix
The prefix for short flags.
Definition: args.hxx:646
bool addDefault
Add default values to argument description.
Definition: args.hxx:750
std::string shortSeparator
The separator for short flags.
Definition: args.hxx:654
std::string proglineValueClose
The postfix for progline value.
Definition: args.hxx:686
bool useValueNameOnce
Display value name after all the long and short flags.
Definition: args.hxx:722
std::string defaultString
The prefix for default values.
Definition: args.hxx:754
std::string proglineRequiredOpen
The prefix for progline required argument.
Definition: args.hxx:690
bool addChoices
Add choices to argument description.
Definition: args.hxx:742
std::string choiceString
The prefix for choices.
Definition: args.hxx:746
A number of arguments which can be consumed by an option.
Definition: args.hxx:762
A default Reader class for argument classes.
Definition: args.hxx:3294