1 /* A simple header-only C++ argument parser library.
3 * https://github.com/Taywee/args
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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
28 * \brief this single-header lets you use all of the args functionality
30 * The important stuff is done inside the args namespace
36 #define ARGS_VERSION "6.3.0"
37 #define ARGS_VERSION_MAJOR 6
38 #define ARGS_VERSION_MINOR 3
39 #define ARGS_VERSION_PATCH 0
49 #include <unordered_map>
50 #include <unordered_set>
51 #include <type_traits>
56 #if defined(_MSC_VER) && _MSC_VER <= 1800
60 #ifdef ARGS_TESTNAMESPACE
66 * \brief contains all the functionality of the args library
71 /** Getter to grab the value from the argument type.
73 * If the Get() function of the type returns a reference, so does this, and
74 * the value will be modifiable.
76 template <typename Option>
77 auto get(Option &option_) -> decltype(option_.Get())
82 /** (INTERNAL) Count UTF-8 glyphs
84 * This is not reliable, and will fail for combinatory glyphs, but it's
85 * good enough here for now.
87 * \param string The string to count glyphs from
88 * \return The UTF-8 glyphs in the string
90 inline std::string::size_type Glyphs(const std::string &string_)
92 std::string::size_type length = 0;
93 for (const char c: string_)
95 if ((c & 0xc0) != 0x80)
103 /** (INTERNAL) Wrap a vector of words into a vector of lines
105 * Empty words are skipped. Word "\n" forces wrapping.
107 * \param begin The begin iterator
108 * \param end The end iterator
109 * \param width The width of the body
110 * \param firstlinewidth the width of the first line, defaults to the width of the body
111 * \param firstlineindent the indent of the first line, defaults to 0
112 * \return the vector of lines
114 template <typename It>
115 inline std::vector<std::string> Wrap(It begin,
117 const std::string::size_type width,
118 std::string::size_type firstlinewidth = 0,
119 std::string::size_type firstlineindent = 0)
121 std::vector<std::string> output;
122 std::string line(firstlineindent, ' ');
125 if (firstlinewidth == 0)
127 firstlinewidth = width;
130 auto currentwidth = firstlinewidth;
132 for (auto it = begin; it != end; ++it)
143 output.push_back(line);
146 currentwidth = width;
152 auto itemsize = Glyphs(*it);
153 if ((line.length() + 1 + itemsize) > currentwidth)
157 output.push_back(line);
160 currentwidth = width;
178 output.push_back(line);
186 template <typename T>
187 std::string Join(const T& array, const std::string &delimiter)
190 for (auto &element : array)
204 /** (INTERNAL) Wrap a string into a vector of lines
206 * This is quick and hacky, but works well enough. You can specify a
207 * different width for the first line
209 * \param width The width of the body
210 * \param firstlinewid the width of the first line, defaults to the width of the body
211 * \return the vector of lines
213 inline std::vector<std::string> Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0)
215 // Preserve existing line breaks
216 const auto newlineloc = in.find('\n');
217 if (newlineloc != in.npos)
219 auto first = Wrap(std::string(in, 0, newlineloc), width);
220 auto second = Wrap(std::string(in, newlineloc + 1), width);
223 std::make_move_iterator(std::begin(second)),
224 std::make_move_iterator(std::end(second)));
228 std::istringstream stream(in);
229 std::string::size_type indent = 0;
233 if (!std::isspace(static_cast<unsigned char>(c)))
240 return Wrap(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>(),
241 width, firstlinewidth, indent);
245 /// Error class, for when ARGS_NOEXCEPT is defined
262 class Error : public std::runtime_error
265 Error(const std::string &problem) : std::runtime_error(problem) {}
269 /** Errors that occur during usage
271 class UsageError : public Error
274 UsageError(const std::string &problem) : Error(problem) {}
275 virtual ~UsageError() {}
278 /** Errors that occur during regular parsing
280 class ParseError : public Error
283 ParseError(const std::string &problem) : Error(problem) {}
284 virtual ~ParseError() {}
287 /** Errors that are detected from group validation after parsing finishes
289 class ValidationError : public Error
292 ValidationError(const std::string &problem) : Error(problem) {}
293 virtual ~ValidationError() {}
296 /** Errors that when a required flag is omitted
298 class RequiredError : public ValidationError
301 RequiredError(const std::string &problem) : ValidationError(problem) {}
302 virtual ~RequiredError() {}
305 /** Errors in map lookups
307 class MapError : public ParseError
310 MapError(const std::string &problem) : ParseError(problem) {}
311 virtual ~MapError() {}
314 /** Error that occurs when a singular flag is specified multiple times
316 class ExtraError : public ParseError
319 ExtraError(const std::string &problem) : ParseError(problem) {}
320 virtual ~ExtraError() {}
323 /** An exception that indicates that the user has requested help
325 class Help : public Error
328 Help(const std::string &flag) : Error(flag) {}
332 /** (INTERNAL) An exception that emulates coroutine-like control flow for subparsers.
334 class SubparserError : public Error
337 SubparserError() : Error("") {}
338 virtual ~SubparserError() {}
341 /** An exception that contains autocompletion reply
343 class Completion : public Error
346 Completion(const std::string &flag) : Error(flag) {}
347 virtual ~Completion() {}
351 /** A simple unified option type for unified initializer lists for the Matcher class.
356 const char shortFlag;
357 const std::string longFlag;
358 EitherFlag(const std::string &flag) : isShort(false), shortFlag(), longFlag(flag) {}
359 EitherFlag(const char *flag) : isShort(false), shortFlag(), longFlag(flag) {}
360 EitherFlag(const char flag) : isShort(true), shortFlag(flag), longFlag() {}
362 /** Get just the long flags from an initializer list of EitherFlags
364 static std::unordered_set<std::string> GetLong(std::initializer_list<EitherFlag> flags)
366 std::unordered_set<std::string> longFlags;
367 for (const EitherFlag &flag: flags)
371 longFlags.insert(flag.longFlag);
377 /** Get just the short flags from an initializer list of EitherFlags
379 static std::unordered_set<char> GetShort(std::initializer_list<EitherFlag> flags)
381 std::unordered_set<char> shortFlags;
382 for (const EitherFlag &flag: flags)
386 shortFlags.insert(flag.shortFlag);
392 std::string str() const
394 return isShort ? std::string(1, shortFlag) : longFlag;
397 std::string str(const std::string &shortPrefix, const std::string &longPrefix) const
399 return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag;
405 /** A class of "matchers", specifying short and flags that can possibly be
408 * This is supposed to be constructed and then passed in, not used directly
414 const std::unordered_set<char> shortFlags;
415 const std::unordered_set<std::string> longFlags;
418 /** Specify short and long flags separately as iterators
420 * ex: `args::Matcher(shortFlags.begin(), shortFlags.end(), longFlags.begin(), longFlags.end())`
422 template <typename ShortIt, typename LongIt>
423 Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd) :
424 shortFlags(shortFlagsStart, shortFlagsEnd),
425 longFlags(longFlagsStart, longFlagsEnd)
427 if (shortFlags.empty() && longFlags.empty())
429 #ifndef ARGS_NOEXCEPT
430 throw UsageError("empty Matcher");
436 /// Only for ARGS_NOEXCEPT
437 Error GetError() const noexcept
439 return shortFlags.empty() && longFlags.empty() ? Error::Usage : Error::None;
443 /** Specify short and long flags separately as iterables
445 * ex: `args::Matcher(shortFlags, longFlags)`
447 template <typename Short, typename Long>
448 Matcher(Short &&shortIn, Long &&longIn) :
449 Matcher(std::begin(shortIn), std::end(shortIn), std::begin(longIn), std::end(longIn))
452 /** Specify a mixed single initializer-list of both short and long flags
454 * This is the fancy one. It takes a single initializer list of
455 * any number of any mixed kinds of flags. Chars are
456 * automatically interpreted as short flags, and strings are
457 * automatically interpreted as long flags:
460 * args::Matcher{"foo"}
461 * args::Matcher{'h', "help"}
462 * args::Matcher{"foo", 'f', 'F', "FoO"}
464 Matcher(std::initializer_list<EitherFlag> in) :
465 Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {}
467 Matcher(Matcher &&other) noexcept : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags))
472 /** (INTERNAL) Check if there is a match of a short flag
474 bool Match(const char flag) const
476 return shortFlags.find(flag) != shortFlags.end();
479 /** (INTERNAL) Check if there is a match of a long flag
481 bool Match(const std::string &flag) const
483 return longFlags.find(flag) != longFlags.end();
486 /** (INTERNAL) Check if there is a match of a flag
488 bool Match(const EitherFlag &flag) const
490 return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag);
493 /** (INTERNAL) Get all flag strings as a vector, with the prefixes embedded
495 std::vector<EitherFlag> GetFlagStrings() const
497 std::vector<EitherFlag> flagStrings;
498 flagStrings.reserve(shortFlags.size() + longFlags.size());
499 for (const char flag: shortFlags)
501 flagStrings.emplace_back(flag);
503 for (const std::string &flag: longFlags)
505 flagStrings.emplace_back(flag);
510 /** (INTERNAL) Get long flag if it exists or any short flag
512 EitherFlag GetLongOrAny() const
514 if (!longFlags.empty())
516 return *longFlags.begin();
519 if (!shortFlags.empty())
521 return *shortFlags.begin();
524 // should be unreachable
528 /** (INTERNAL) Get short flag if it exists or any long flag
530 EitherFlag GetShortOrAny() const
532 if (!shortFlags.empty())
534 return *shortFlags.begin();
537 if (!longFlags.empty())
539 return *longFlags.begin();
542 // should be unreachable
547 /** Attributes for flags.
555 /** Flag can't be passed multiple times.
559 /** Flag can't be omitted.
563 /** Flag is excluded from usage line.
565 HiddenFromUsage = 0x04,
567 /** Flag is excluded from options help.
569 HiddenFromDescription = 0x08,
571 /** Flag is global and can be used in any subcommand.
575 /** Flag stops a parser.
579 /** Flag is excluded from auto completion.
581 HiddenFromCompletion = 0x40,
583 /** Flag is excluded from options help and usage line
585 Hidden = HiddenFromUsage | HiddenFromDescription | HiddenFromCompletion,
588 inline Options operator | (Options lhs, Options rhs)
590 return static_cast<Options>(static_cast<int>(lhs) | static_cast<int>(rhs));
593 inline Options operator & (Options lhs, Options rhs)
595 return static_cast<Options>(static_cast<int>(lhs) & static_cast<int>(rhs));
599 class PositionalBase;
601 class ArgumentParser;
603 /** A simple structure of parameters for easy user-modifyable help menus
607 /** The width of the help menu
609 unsigned int width = 80;
610 /** The indent of the program line
612 unsigned int progindent = 2;
613 /** The indent of the program trailing lines for long parameters
615 unsigned int progtailindent = 4;
616 /** The indent of the description and epilogs
618 unsigned int descriptionindent = 4;
619 /** The indent of the flags
621 unsigned int flagindent = 6;
622 /** The indent of the flag descriptions
624 unsigned int helpindent = 40;
625 /** The additional indent each group adds
627 unsigned int eachgroupindent = 2;
629 /** The minimum gutter between each flag and its help
631 unsigned int gutter = 1;
633 /** Show the terminator when both options and positional parameters are present
635 bool showTerminator = true;
637 /** Show the {OPTIONS} on the prog line when this is true
639 bool showProglineOptions = true;
641 /** Show the positionals on the prog line when this is true
643 bool showProglinePositionals = true;
645 /** The prefix for short flags
647 std::string shortPrefix;
649 /** The prefix for long flags
651 std::string longPrefix;
653 /** The separator for short flags
655 std::string shortSeparator;
657 /** The separator for long flags
659 std::string longSeparator;
661 /** The program name for help generation
663 std::string programName;
665 /** Show command's flags
667 bool showCommandChildren = false;
669 /** Show command's descriptions and epilog
671 bool showCommandFullHelp = false;
673 /** The postfix for progline when showProglineOptions is true and command has any flags
675 std::string proglineOptions = "{OPTIONS}";
677 /** The prefix for progline when command has any subcommands
679 std::string proglineCommand = "COMMAND";
681 /** The prefix for progline value
683 std::string proglineValueOpen = " <";
685 /** The postfix for progline value
687 std::string proglineValueClose = ">";
689 /** The prefix for progline required argument
691 std::string proglineRequiredOpen = "";
693 /** The postfix for progline required argument
695 std::string proglineRequiredClose = "";
697 /** The prefix for progline non-required argument
699 std::string proglineNonrequiredOpen = "[";
701 /** The postfix for progline non-required argument
703 std::string proglineNonrequiredClose = "]";
705 /** Show flags in program line
707 bool proglineShowFlags = false;
709 /** Use short flags in program lines when possible
711 bool proglinePreferShortFlags = false;
713 /** Program line prefix
715 std::string usageString;
717 /** String shown in help before flags descriptions
719 std::string optionsString = "OPTIONS:";
721 /** Display value name after all the long and short flags
723 bool useValueNameOnce = false;
727 bool showValueName = true;
729 /** Add newline before flag description
731 bool addNewlineBeforeDescription = false;
733 /** The prefix for option value
735 std::string valueOpen = "[";
737 /** The postfix for option value
739 std::string valueClose = "]";
741 /** Add choices to argument description
743 bool addChoices = false;
745 /** The prefix for choices
747 std::string choiceString = "\nOne of: ";
749 /** Add default values to argument description
751 bool addDefault = false;
753 /** The prefix for default values
755 std::string defaultString = "\nDefault: ";
758 /** A number of arguments which can be consumed by an option.
760 * Represents a closed interval [min, max].
767 Nargs(size_t min_, size_t max_) : min{min_}, max{max_}
769 #ifndef ARGS_NOEXCEPT
772 throw UsageError("Nargs: max > min");
777 Nargs(size_t num_) : min{num_}, max{num_}
781 friend bool operator == (const Nargs &lhs, const Nargs &rhs)
783 return lhs.min == rhs.min && lhs.max == rhs.max;
786 friend bool operator != (const Nargs &lhs, const Nargs &rhs)
788 return !(lhs == rhs);
792 /** Base class for all match types
797 Options options = {};
800 bool matched = false;
801 const std::string help;
803 /// Only for ARGS_NOEXCEPT
804 mutable Error error = Error::None;
805 mutable std::string errorMsg;
809 Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {}
812 Options GetOptions() const noexcept
817 bool IsRequired() const noexcept
819 return (GetOptions() & Options::Required) != Options::None;
822 virtual bool Matched() const noexcept
827 virtual void Validate(const std::string &, const std::string &) const
831 operator bool() const noexcept
836 virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &, const unsigned indentLevel) const
838 std::tuple<std::string, std::string, unsigned> description;
839 std::get<1>(description) = help;
840 std::get<2>(description) = indentLevel;
841 return { std::move(description) };
844 virtual std::vector<Command*> GetCommands()
849 virtual bool IsGroup() const
854 virtual FlagBase *Match(const EitherFlag &)
859 virtual PositionalBase *GetNextPositional()
864 virtual std::vector<FlagBase*> GetAllFlags()
869 virtual bool HasFlag() const
874 virtual bool HasPositional() const
879 virtual bool HasCommand() const
884 virtual std::vector<std::string> GetProgramLine(const HelpParams &) const
889 /// Sets a kick-out value for building subparsers
890 void KickOut(bool kickout_) noexcept
894 options = options | Options::KickOut;
898 options = static_cast<Options>(static_cast<int>(options) & ~static_cast<int>(Options::KickOut));
902 /// Gets the kick-out value for building subparsers
903 bool KickOut() const noexcept
905 return (options & Options::KickOut) != Options::None;
908 virtual void Reset() noexcept
918 /// Only for ARGS_NOEXCEPT
919 virtual Error GetError() const
924 /// Only for ARGS_NOEXCEPT
925 std::string GetErrorMsg() const
932 /** Base class for all match types that have a name
934 class NamedBase : public Base
937 const std::string name;
938 bool kickout = false;
939 std::string defaultString;
940 bool defaultStringManual = false;
941 std::vector<std::string> choicesStrings;
942 bool choicesStringManual = false;
944 virtual std::string GetDefaultString(const HelpParams&) const { return {}; }
946 virtual std::vector<std::string> GetChoicesStrings(const HelpParams&) const { return {}; }
948 virtual std::string GetNameString(const HelpParams&) const { return Name(); }
950 void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const
952 if (isManual && !manual.empty())
957 else if (!isManual && isGenerated && !generated.empty())
965 NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {}
966 virtual ~NamedBase() {}
968 /** Sets default value string that will be added to argument description.
969 * Use empty string to disable it for this argument.
971 void HelpDefault(const std::string &str)
973 defaultStringManual = true;
977 /** Gets default value string that will be added to argument description.
979 std::string HelpDefault(const HelpParams ¶ms) const
981 return defaultStringManual ? defaultString : GetDefaultString(params);
984 /** Sets choices strings that will be added to argument description.
985 * Use empty vector to disable it for this argument.
987 void HelpChoices(const std::vector<std::string> &array)
989 choicesStringManual = true;
990 choicesStrings = array;
993 /** Gets choices strings that will be added to argument description.
995 std::vector<std::string> HelpChoices(const HelpParams ¶ms) const
997 return choicesStringManual ? choicesStrings : GetChoicesStrings(params);
1000 virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams ¶ms, const unsigned indentLevel) const override
1002 std::tuple<std::string, std::string, unsigned> description;
1003 std::get<0>(description) = GetNameString(params);
1004 std::get<1>(description) = help;
1005 std::get<2>(description) = indentLevel;
1007 AddDescriptionPostfix(std::get<1>(description), choicesStringManual, detail::Join(choicesStrings, ", "), params.addChoices, detail::Join(GetChoicesStrings(params), ", "), params.choiceString);
1008 AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString);
1010 return { std::move(description) };
1013 virtual std::string Name() const
1021 template<typename T>
1022 using vector = std::vector<T, std::allocator<T>>;
1024 template<typename K, typename T>
1025 using unordered_map = std::unordered_map<K, T, std::hash<K>,
1026 std::equal_to<K>, std::allocator<std::pair<const K, T> > >;
1028 template<typename S, typename T>
1031 template<typename SS, typename TT>
1032 static auto test(int)
1033 -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
1035 template<typename, typename>
1036 static auto test(...) -> std::false_type;
1039 using type = decltype(test<S,T>(0));
1042 template <typename T>
1043 using IsConvertableToString = typename is_streamable<std::ostringstream, T>::type;
1045 template <typename T>
1046 typename std::enable_if<IsConvertableToString<T>::value, std::string>::type
1047 ToString(const T &value)
1049 std::ostringstream s;
1054 template <typename T>
1055 typename std::enable_if<!IsConvertableToString<T>::value, std::string>::type
1061 template <typename T>
1062 std::vector<std::string> MapKeysToStrings(const T &map)
1064 std::vector<std::string> res;
1065 using K = typename std::decay<decltype(std::begin(map)->first)>::type;
1066 if (IsConvertableToString<K>::value)
1068 for (const auto &p : map)
1070 res.push_back(detail::ToString(p.first));
1073 std::sort(res.begin(), res.end());
1079 /** Base class for all flag options
1081 class FlagBase : public NamedBase
1084 const Matcher matcher;
1086 virtual std::string GetNameString(const HelpParams ¶ms) const override
1088 const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name();
1090 const auto flagStrings = matcher.GetFlagStrings();
1091 const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce;
1092 for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it)
1095 if (it != flagStrings.begin())
1100 flags += flag.isShort ? params.shortPrefix : params.longPrefix;
1101 flags += flag.str();
1103 if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end()))
1105 flags += flag.isShort ? params.shortSeparator : params.longSeparator;
1106 flags += params.valueOpen + postfix + params.valueClose;
1114 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_)) {}
1116 FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {}
1118 virtual ~FlagBase() {}
1120 virtual FlagBase *Match(const EitherFlag &flag) override
1122 if (matcher.Match(flag))
1124 if ((GetOptions() & Options::Single) != Options::None && matched)
1126 std::ostringstream problem;
1127 problem << "Flag '" << flag.str() << "' was passed multiple times, but is only allowed to be passed once";
1128 #ifdef ARGS_NOEXCEPT
1129 error = Error::Extra;
1130 errorMsg = problem.str();
1132 throw ExtraError(problem.str());
1141 virtual std::vector<FlagBase*> GetAllFlags() override
1146 const Matcher &GetMatcher() const
1151 virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1153 if (!Matched() && IsRequired())
1155 std::ostringstream problem;
1156 problem << "Flag '" << matcher.GetLongOrAny().str(shortPrefix, longPrefix) << "' is required";
1157 #ifdef ARGS_NOEXCEPT
1158 error = Error::Required;
1159 errorMsg = problem.str();
1161 throw RequiredError(problem.str());
1166 virtual std::vector<std::string> GetProgramLine(const HelpParams ¶ms) const override
1168 if (!params.proglineShowFlags)
1173 const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name();
1174 const EitherFlag flag = params.proglinePreferShortFlags ? matcher.GetShortOrAny() : matcher.GetLongOrAny();
1175 std::string res = flag.str(params.shortPrefix, params.longPrefix);
1176 if (!postfix.empty())
1178 res += params.proglineValueOpen + postfix + params.proglineValueClose;
1181 return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose
1182 : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose };
1185 virtual bool HasFlag() const override
1190 #ifdef ARGS_NOEXCEPT
1191 /// Only for ARGS_NOEXCEPT
1192 virtual Error GetError() const override
1194 const auto nargs = NumberOfArguments();
1195 if (nargs.min > nargs.max)
1197 return Error::Usage;
1200 const auto matcherError = matcher.GetError();
1201 if (matcherError != Error::None)
1203 return matcherError;
1210 /** Defines how many values can be consumed by this option.
1212 * \return closed interval [min, max]
1214 virtual Nargs NumberOfArguments() const noexcept = 0;
1216 /** Parse values of this option.
1218 * \param value Vector of values. It's size must be in NumberOfArguments() interval.
1220 virtual void ParseValue(const std::vector<std::string> &value) = 0;
1223 /** Base class for value-accepting flag options
1225 class ValueFlagBase : public FlagBase
1228 ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : FlagBase(name_, help_, std::move(matcher_), extraError_) {}
1229 ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : FlagBase(name_, help_, std::move(matcher_), options_) {}
1230 virtual ~ValueFlagBase() {}
1232 virtual Nargs NumberOfArguments() const noexcept override
1238 class CompletionFlag : public ValueFlagBase
1241 std::vector<std::string> reply;
1245 template <typename GroupClass>
1246 CompletionFlag(GroupClass &group_, Matcher &&matcher_): ValueFlagBase("completion", "completion flag", std::move(matcher_), Options::Hidden)
1248 group_.AddCompletion(*this);
1251 virtual ~CompletionFlag() {}
1253 virtual Nargs NumberOfArguments() const noexcept override
1258 virtual void ParseValue(const std::vector<std::string> &value_) override
1260 syntax = value_.at(0);
1261 std::istringstream(value_.at(1)) >> cword;
1264 /** Get the completion reply
1266 std::string Get() noexcept
1268 return detail::Join(reply, "\n");
1271 virtual void Reset() noexcept override
1273 ValueFlagBase::Reset();
1281 /** Base class for positional options
1283 class PositionalBase : public NamedBase
1289 PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {}
1290 virtual ~PositionalBase() {}
1297 virtual void ParseValue(const std::string &value_) = 0;
1299 virtual void Reset() noexcept override
1303 #ifdef ARGS_NOEXCEPT
1304 error = Error::None;
1309 virtual PositionalBase *GetNextPositional() override
1311 return Ready() ? this : nullptr;
1314 virtual bool HasPositional() const override
1319 virtual std::vector<std::string> GetProgramLine(const HelpParams ¶ms) const override
1321 return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose
1322 : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose };
1325 virtual void Validate(const std::string &, const std::string &) const override
1327 if (IsRequired() && !Matched())
1329 std::ostringstream problem;
1330 problem << "Option '" << Name() << "' is required";
1331 #ifdef ARGS_NOEXCEPT
1332 error = Error::Required;
1333 errorMsg = problem.str();
1335 throw RequiredError(problem.str());
1341 /** Class for all kinds of validating groups, including ArgumentParser
1343 class Group : public Base
1346 std::vector<Base*> children;
1347 std::function<bool(const Group &)> validator;
1350 /** Default validators
1354 static bool Xor(const Group &group)
1356 return group.MatchedChildren() == 1;
1359 static bool AtLeastOne(const Group &group)
1361 return group.MatchedChildren() >= 1;
1364 static bool AtMostOne(const Group &group)
1366 return group.MatchedChildren() <= 1;
1369 static bool All(const Group &group)
1371 return group.Children().size() == group.MatchedChildren();
1374 static bool AllOrNone(const Group &group)
1376 return (All(group) || None(group));
1379 static bool AllChildGroups(const Group &group)
1381 return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool {
1382 return child->IsGroup() && !child->Matched();
1386 static bool DontCare(const Group &)
1391 static bool CareTooMuch(const Group &)
1396 static bool None(const Group &group)
1398 return group.MatchedChildren() == 0;
1401 /// If help is empty, this group will not be printed in help output
1402 Group(const std::string &help_ = std::string(), const std::function<bool(const Group &)> &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) {}
1403 /// If help is empty, this group will not be printed in help output
1404 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_)
1410 /** Append a child to this Group.
1412 void Add(Base &child)
1414 children.emplace_back(&child);
1417 /** Get all this group's children
1419 const std::vector<Base *> &Children() const
1424 /** Return the first FlagBase that matches flag, or nullptr
1426 * \param flag The flag with prefixes stripped
1427 * \return the first matching FlagBase pointer, or nullptr if there is no match
1429 virtual FlagBase *Match(const EitherFlag &flag) override
1431 for (Base *child: Children())
1433 if (FlagBase *match = child->Match(flag))
1441 virtual std::vector<FlagBase*> GetAllFlags() override
1443 std::vector<FlagBase*> res;
1444 for (Base *child: Children())
1446 auto childRes = child->GetAllFlags();
1447 res.insert(res.end(), childRes.begin(), childRes.end());
1452 virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1454 for (Base *child: Children())
1456 child->Validate(shortPrefix, longPrefix);
1460 /** Get the next ready positional, or nullptr if there is none
1462 * \return the first ready PositionalBase pointer, or nullptr if there is no match
1464 virtual PositionalBase *GetNextPositional() override
1466 for (Base *child: Children())
1468 if (auto next = child->GetNextPositional())
1476 /** Get whether this has any FlagBase children
1478 * \return Whether or not there are any FlagBase children
1480 virtual bool HasFlag() const override
1482 return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); });
1485 /** Get whether this has any PositionalBase children
1487 * \return Whether or not there are any PositionalBase children
1489 virtual bool HasPositional() const override
1491 return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); });
1494 /** Get whether this has any Command children
1496 * \return Whether or not there are any Command children
1498 virtual bool HasCommand() const override
1500 return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); });
1503 /** Count the number of matched children this group has
1505 std::vector<Base *>::size_type MatchedChildren() const
1507 // Cast to avoid warnings from -Wsign-conversion
1508 return static_cast<std::vector<Base *>::size_type>(
1509 std::count_if(std::begin(Children()), std::end(Children()), [](const Base *child){return child->Matched();}));
1512 /** Whether or not this group matches validation
1514 virtual bool Matched() const noexcept override
1516 return validator(*this);
1526 /** Get all the child descriptions for help generation
1528 virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams ¶ms, const unsigned int indent) const override
1530 std::vector<std::tuple<std::string, std::string, unsigned int>> descriptions;
1532 // Push that group description on the back if not empty
1533 unsigned addindent = 0;
1536 descriptions.emplace_back(help, "", indent);
1540 for (Base *child: Children())
1542 if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
1547 auto groupDescriptions = child->GetDescription(params, indent + addindent);
1548 descriptions.insert(
1549 std::end(descriptions),
1550 std::make_move_iterator(std::begin(groupDescriptions)),
1551 std::make_move_iterator(std::end(groupDescriptions)));
1553 return descriptions;
1556 /** Get the names of positional parameters
1558 virtual std::vector<std::string> GetProgramLine(const HelpParams ¶ms) const override
1560 std::vector <std::string> names;
1561 for (Base *child: Children())
1563 if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None)
1568 auto groupNames = child->GetProgramLine(params);
1571 std::make_move_iterator(std::begin(groupNames)),
1572 std::make_move_iterator(std::end(groupNames)));
1577 virtual std::vector<Command*> GetCommands() override
1579 std::vector<Command*> res;
1580 for (const auto &child : Children())
1582 auto subparsers = child->GetCommands();
1583 res.insert(std::end(res), std::begin(subparsers), std::end(subparsers));
1588 virtual bool IsGroup() const override
1593 virtual void Reset() noexcept override
1597 for (auto &child: Children())
1601 #ifdef ARGS_NOEXCEPT
1602 error = Error::None;
1607 #ifdef ARGS_NOEXCEPT
1608 /// Only for ARGS_NOEXCEPT
1609 virtual Error GetError() const override
1611 if (error != Error::None)
1616 auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;});
1617 if (it == Children().end())
1622 return (*it)->GetError();
1629 /** Class for using global options in ArgumentParser.
1631 class GlobalOptions : public Group
1634 GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global)
1640 /** Utility class for building subparsers with coroutines/callbacks.
1644 * Command command(argumentParser, "command", "my command", [](args::Subparser &s)
1646 * // your command flags/positionals
1647 * s.Parse(); //required
1648 * //your command code
1652 * For ARGS_NOEXCEPT mode don't forget to check `s.GetError()` after `s.Parse()`
1653 * and return if it isn't equals to args::Error::None.
1657 class Subparser : public Group
1660 std::vector<std::string> args;
1661 std::vector<std::string> kicked;
1662 ArgumentParser *parser = nullptr;
1663 const HelpParams &helpParams;
1664 const Command &command;
1665 bool isParsed = false;
1668 Subparser(std::vector<std::string> args_, ArgumentParser &parser_, const Command &command_, const HelpParams &helpParams_)
1669 : Group({}, Validators::AllChildGroups), args(std::move(args_)), parser(&parser_), helpParams(helpParams_), command(command_)
1673 Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_)
1677 Subparser(const Subparser&) = delete;
1678 Subparser(Subparser&&) = delete;
1679 Subparser &operator = (const Subparser&) = delete;
1680 Subparser &operator = (Subparser&&) = delete;
1682 const Command &GetCommand()
1687 /** (INTERNAL) Determines whether Parse was called or not.
1689 bool IsParsed() const
1694 /** Continue parsing arguments for new command.
1698 /** Returns a vector of kicked out arguments.
1702 const std::vector<std::string> &KickedOut() const noexcept
1708 /** Main class for building subparsers.
1712 class Command : public Group
1715 friend class Subparser;
1719 std::string description;
1721 std::string proglinePostfix;
1723 std::function<void(Subparser&)> parserCoroutine;
1724 bool commandIsRequired = true;
1725 Command *selectedCommand = nullptr;
1727 mutable std::vector<std::tuple<std::string, std::string, unsigned>> subparserDescription;
1728 mutable std::vector<std::string> subparserProgramLine;
1729 mutable bool subparserHasFlag = false;
1730 mutable bool subparserHasPositional = false;
1731 mutable bool subparserHasCommand = false;
1732 #ifdef ARGS_NOEXCEPT
1733 mutable Error subparserError = Error::None;
1735 mutable Subparser *subparser = nullptr;
1742 RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_);
1743 RaiiSubparser(const Command &command_, const HelpParams ¶ms_);
1747 command.subparser = oldSubparser;
1756 const Command &command;
1758 Subparser *oldSubparser;
1761 Command() = default;
1763 std::function<void(Subparser&)> &GetCoroutine()
1765 return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine;
1768 Command &SelectedCommand()
1770 Command *res = this;
1771 while (res->selectedCommand != nullptr)
1773 res = res->selectedCommand;
1779 const Command &SelectedCommand() const
1781 const Command *res = this;
1782 while (res->selectedCommand != nullptr)
1784 res = res->selectedCommand;
1790 void UpdateSubparserHelp(const HelpParams ¶ms) const
1792 if (parserCoroutine)
1794 RaiiSubparser coro(*this, params);
1795 #ifndef ARGS_NOEXCEPT
1798 parserCoroutine(coro.Parser());
1800 catch (args::SubparserError&)
1804 parserCoroutine(coro.Parser());
1810 Command(Group &base_, std::string name_, std::string help_, std::function<void(Subparser&)> coroutine_ = {})
1811 : name(std::move(name_)), help(std::move(help_)), parserCoroutine(std::move(coroutine_))
1816 /** The description that appears on the prog line after options
1818 const std::string &ProglinePostfix() const
1819 { return proglinePostfix; }
1821 /** The description that appears on the prog line after options
1823 void ProglinePostfix(const std::string &proglinePostfix_)
1824 { this->proglinePostfix = proglinePostfix_; }
1826 /** The description that appears above options
1828 const std::string &Description() const
1829 { return description; }
1830 /** The description that appears above options
1833 void Description(const std::string &description_)
1834 { this->description = description_; }
1836 /** The description that appears below options
1838 const std::string &Epilog() const
1841 /** The description that appears below options
1843 void Epilog(const std::string &epilog_)
1844 { this->epilog = epilog_; }
1846 /** The name of command
1848 const std::string &Name() const
1851 /** The description of command
1853 const std::string &Help() const
1856 /** If value is true, parser will fail if no command was parsed.
1860 void RequireCommand(bool value)
1861 { commandIsRequired = value; }
1863 virtual bool IsGroup() const override
1866 virtual bool Matched() const noexcept override
1867 { return Base::Matched(); }
1869 operator bool() const noexcept
1870 { return Matched(); }
1872 void Match() noexcept
1875 void SelectCommand(Command *c) noexcept
1877 selectedCommand = c;
1885 virtual FlagBase *Match(const EitherFlag &flag) override
1887 if (selectedCommand != nullptr)
1889 if (auto *res = selectedCommand->Match(flag))
1894 for (auto *child: Children())
1896 if ((child->GetOptions() & Options::Global) != Options::None)
1898 if (auto *res = child->Match(flag))
1908 if (subparser != nullptr)
1910 return subparser->Match(flag);
1913 return Matched() ? Group::Match(flag) : nullptr;
1916 virtual std::vector<FlagBase*> GetAllFlags() override
1918 std::vector<FlagBase*> res;
1925 for (auto *child: Children())
1927 if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None)
1929 auto childFlags = child->GetAllFlags();
1930 res.insert(res.end(), childFlags.begin(), childFlags.end());
1934 if (selectedCommand != nullptr)
1936 auto childFlags = selectedCommand->GetAllFlags();
1937 res.insert(res.end(), childFlags.begin(), childFlags.end());
1940 if (subparser != nullptr)
1942 auto childFlags = subparser->GetAllFlags();
1943 res.insert(res.end(), childFlags.begin(), childFlags.end());
1949 virtual PositionalBase *GetNextPositional() override
1951 if (selectedCommand != nullptr)
1953 if (auto *res = selectedCommand->GetNextPositional())
1958 for (auto *child: Children())
1960 if ((child->GetOptions() & Options::Global) != Options::None)
1962 if (auto *res = child->GetNextPositional())
1972 if (subparser != nullptr)
1974 return subparser->GetNextPositional();
1977 return Matched() ? Group::GetNextPositional() : nullptr;
1980 virtual bool HasFlag() const override
1982 return subparserHasFlag || Group::HasFlag();
1985 virtual bool HasPositional() const override
1987 return subparserHasPositional || Group::HasPositional();
1990 virtual bool HasCommand() const override
1995 std::vector<std::string> GetCommandProgramLine(const HelpParams ¶ms) const
1997 UpdateSubparserHelp(params);
1999 auto res = Group::GetProgramLine(params);
2000 res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end());
2002 if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand))
2004 res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]");
2007 if (!Name().empty())
2009 res.insert(res.begin(), Name());
2012 if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags)
2014 res.push_back(params.proglineOptions);
2017 if (!ProglinePostfix().empty())
2020 for (auto c : ProglinePostfix())
2022 if (std::isspace(static_cast<unsigned char>(c)))
2026 res.push_back(line);
2032 res.push_back("\n");
2043 res.push_back(line);
2050 virtual std::vector<std::string> GetProgramLine(const HelpParams ¶ms) const override
2057 return GetCommandProgramLine(params);
2060 virtual std::vector<Command*> GetCommands() override
2062 if (selectedCommand != nullptr)
2064 return selectedCommand->GetCommands();
2069 return Group::GetCommands();
2075 virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams ¶ms, const unsigned int indent) const override
2077 std::vector<std::tuple<std::string, std::string, unsigned>> descriptions;
2078 unsigned addindent = 0;
2080 UpdateSubparserHelp(params);
2084 if (params.showCommandFullHelp)
2086 std::ostringstream s;
2088 for (const auto &progline: GetCommandProgramLine(params))
2102 descriptions.emplace_back(s.str(), "", indent);
2106 descriptions.emplace_back(Name(), help, indent);
2109 if (!params.showCommandChildren && !params.showCommandFullHelp)
2111 return descriptions;
2117 if (params.showCommandFullHelp && !Matched())
2119 descriptions.emplace_back("", "", indent + addindent);
2120 descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent);
2121 descriptions.emplace_back("", "", indent + addindent);
2124 for (Base *child: Children())
2126 if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
2131 auto groupDescriptions = child->GetDescription(params, indent + addindent);
2132 descriptions.insert(
2133 std::end(descriptions),
2134 std::make_move_iterator(std::begin(groupDescriptions)),
2135 std::make_move_iterator(std::end(groupDescriptions)));
2138 for (auto childDescription: subparserDescription)
2140 std::get<2>(childDescription) += indent + addindent;
2141 descriptions.push_back(std::move(childDescription));
2144 if (params.showCommandFullHelp && !Matched())
2146 descriptions.emplace_back("", "", indent + addindent);
2147 if (!Epilog().empty())
2149 descriptions.emplace_back(Epilog(), "", indent + addindent);
2150 descriptions.emplace_back("", "", indent + addindent);
2154 return descriptions;
2157 virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override
2164 auto onValidationError = [&]
2166 std::ostringstream problem;
2167 problem << "Group validation failed somewhere!";
2168 #ifdef ARGS_NOEXCEPT
2169 error = Error::Validation;
2170 errorMsg = problem.str();
2172 throw ValidationError(problem.str());
2176 for (Base *child: Children())
2178 if (child->IsGroup() && !child->Matched())
2180 onValidationError();
2183 child->Validate(shortprefix, longprefix);
2186 if (subparser != nullptr)
2188 subparser->Validate(shortprefix, longprefix);
2189 if (!subparser->Matched())
2191 onValidationError();
2195 if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand))
2197 std::ostringstream problem;
2198 problem << "Command is required";
2199 #ifdef ARGS_NOEXCEPT
2200 error = Error::Validation;
2201 errorMsg = problem.str();
2203 throw ValidationError(problem.str());
2208 virtual void Reset() noexcept override
2211 selectedCommand = nullptr;
2212 subparserProgramLine.clear();
2213 subparserDescription.clear();
2214 subparserHasFlag = false;
2215 subparserHasPositional = false;
2216 subparserHasCommand = false;
2217 #ifdef ARGS_NOEXCEPT
2218 subparserError = Error::None;
2222 #ifdef ARGS_NOEXCEPT
2223 /// Only for ARGS_NOEXCEPT
2224 virtual Error GetError() const override
2231 if (error != Error::None)
2236 if (subparserError != Error::None)
2238 return subparserError;
2241 return Group::GetError();
2246 /** The main user facing command line argument parser class
2248 class ArgumentParser : public Command
2250 friend class Subparser;
2253 std::string longprefix;
2254 std::string shortprefix;
2256 std::string longseparator;
2258 std::string terminator;
2260 bool allowJoinedShortValue = true;
2261 bool allowJoinedLongValue = true;
2262 bool allowSeparateShortValue = true;
2263 bool allowSeparateLongValue = true;
2265 CompletionFlag *completion = nullptr;
2266 bool readCompletion = false;
2269 enum class OptionType
2276 OptionType ParseOption(const std::string &s, bool allowEmpty = false)
2278 if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length()))
2280 return OptionType::LongFlag;
2283 if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length()))
2285 return OptionType::ShortFlag;
2288 return OptionType::Positional;
2291 template <typename It>
2292 bool Complete(FlagBase &flag, It it, It end)
2295 if (!readCompletion || (++nextIt != end))
2300 const auto &chunk = *it;
2301 for (auto &choice : flag.HelpChoices(helpParams))
2303 AddCompletionReply(chunk, choice);
2306 #ifndef ARGS_NOEXCEPT
2307 throw Completion(completion->Get());
2313 /** (INTERNAL) Parse flag's values
2315 * \param arg The string to display in error message as a flag name
2316 * \param[in, out] it The iterator to first value. It will point to the last value
2317 * \param end The end iterator
2318 * \param joinedArg Joined value (e.g. bar in --foo=bar)
2319 * \param canDiscardJoined If true joined value can be parsed as flag not as a value (as in -abcd)
2320 * \param[out] values The vector to store parsed arg's values
2322 template <typename It>
2323 std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end,
2324 const bool allowSeparate, const bool allowJoined,
2325 const bool hasJoined, const std::string &joinedArg,
2326 const bool canDiscardJoined, std::vector<std::string> &values)
2330 Nargs nargs = flag.NumberOfArguments();
2332 if (hasJoined && !allowJoined && nargs.min != 0)
2334 return "Flag '" + arg + "' was passed a joined argument, but these are disallowed";
2339 if (!canDiscardJoined || nargs.max != 0)
2341 values.push_back(joinedArg);
2343 } else if (!allowSeparate)
2347 return "Flag '" + arg + "' was passed a separate argument, but these are disallowed";
2354 while (valueIt != end &&
2355 values.size() < nargs.max &&
2356 (values.size() < nargs.min || ParseOption(*valueIt) == OptionType::Positional))
2358 if (Complete(flag, valueIt, end))
2364 values.push_back(*valueIt);
2370 if (values.size() > nargs.max)
2372 return "Passed an argument into a non-argument flag: " + arg;
2373 } else if (values.size() < nargs.min)
2375 if (nargs.min == 1 && nargs.max == 1)
2377 return "Flag '" + arg + "' requires an argument but received none";
2378 } else if (nargs.min == 1)
2380 return "Flag '" + arg + "' requires at least one argument but received none";
2381 } else if (nargs.min != nargs.max)
2383 return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) +
2384 " arguments but received " + std::to_string(values.size());
2387 return "Flag '" + arg + "' requires " + std::to_string(nargs.min) +
2388 " arguments but received " + std::to_string(values.size());
2395 template <typename It>
2396 bool ParseLong(It &it, It end)
2398 const auto &chunk = *it;
2399 const auto argchunk = chunk.substr(longprefix.size());
2400 // Try to separate it, in case of a separator:
2401 const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator);
2402 // If the separator is in the argument, separate it.
2403 const auto arg = (separator != argchunk.npos ?
2404 std::string(argchunk, 0, separator)
2406 const auto joined = (separator != argchunk.npos ?
2407 argchunk.substr(separator + longseparator.size())
2410 if (auto flag = Match(arg))
2412 std::vector<std::string> values;
2413 const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue,
2414 separator != argchunk.npos, joined, false, values);
2415 if (!errorMessage.empty())
2417 #ifndef ARGS_NOEXCEPT
2418 throw ParseError(errorMessage);
2420 error = Error::Parse;
2421 errorMsg = errorMessage;
2426 if (!readCompletion)
2428 flag->ParseValue(values);
2431 if (flag->KickOut())
2438 const std::string errorMessage("Flag could not be matched: " + arg);
2439 #ifndef ARGS_NOEXCEPT
2440 throw ParseError(errorMessage);
2442 error = Error::Parse;
2443 errorMsg = errorMessage;
2451 template <typename It>
2452 bool ParseShort(It &it, It end)
2454 const auto &chunk = *it;
2455 const auto argchunk = chunk.substr(shortprefix.size());
2456 for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit)
2458 const auto arg = *argit;
2460 if (auto flag = Match(arg))
2462 const std::string value(argit + 1, std::end(argchunk));
2463 std::vector<std::string> values;
2464 const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end,
2465 allowSeparateShortValue, allowJoinedShortValue,
2466 !value.empty(), value, !value.empty(), values);
2468 if (!errorMessage.empty())
2470 #ifndef ARGS_NOEXCEPT
2471 throw ParseError(errorMessage);
2473 error = Error::Parse;
2474 errorMsg = errorMessage;
2479 if (!readCompletion)
2481 flag->ParseValue(values);
2484 if (flag->KickOut())
2490 if (!values.empty())
2496 const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'");
2497 #ifndef ARGS_NOEXCEPT
2498 throw ParseError(errorMessage);
2500 error = Error::Parse;
2501 errorMsg = errorMessage;
2510 bool AddCompletionReply(const std::string &cur, const std::string &choice)
2512 if (cur.empty() || choice.find(cur) == 0)
2514 if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos)
2516 completion->reply.push_back(choice.substr(choice.find(longseparator) + 1));
2519 completion->reply.push_back(choice);
2527 template <typename It>
2528 bool Complete(It it, It end)
2531 if (!readCompletion || (++nextIt != end))
2536 const auto &chunk = *it;
2537 auto pos = GetNextPositional();
2538 std::vector<Command *> commands = GetCommands();
2539 const auto optionType = ParseOption(chunk, true);
2541 if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
2543 for (auto &cmd : commands)
2545 if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2547 AddCompletionReply(chunk, cmd->Name());
2552 bool hasPositionalCompletion = true;
2554 if (!commands.empty())
2556 for (auto &cmd : commands)
2558 if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2560 AddCompletionReply(chunk, cmd->Name());
2565 if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2567 auto choices = pos->HelpChoices(helpParams);
2568 hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
2569 for (auto &choice : choices)
2571 AddCompletionReply(chunk, choice);
2576 if (hasPositionalCompletion)
2578 auto flags = GetAllFlags();
2579 for (auto flag : flags)
2581 if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None)
2586 auto &matcher = flag->GetMatcher();
2587 if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix)))
2589 for (auto &flagName : matcher.GetFlagStrings())
2591 if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix)))
2599 if (optionType == OptionType::LongFlag && allowJoinedLongValue)
2601 const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
2602 if (separator != chunk.npos)
2604 std::string arg(chunk, 0, separator);
2605 if (auto flag = this->Match(arg.substr(longprefix.size())))
2607 for (auto &choice : flag->HelpChoices(helpParams))
2609 AddCompletionReply(chunk, arg + longseparator + choice);
2613 } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
2615 if (chunk.size() > shortprefix.size() + 1)
2617 auto arg = chunk.at(shortprefix.size());
2618 //TODO: support -abcVALUE where a and b take no value
2619 if (auto flag = this->Match(arg))
2621 for (auto &choice : flag->HelpChoices(helpParams))
2623 AddCompletionReply(chunk, shortprefix + arg + choice);
2631 #ifndef ARGS_NOEXCEPT
2632 throw Completion(completion->Get());
2638 template <typename It>
2639 It Parse(It begin, It end)
2641 bool terminated = false;
2642 std::vector<Command *> commands = GetCommands();
2644 // Check all arg chunks
2645 for (auto it = begin; it != end; ++it)
2647 if (Complete(it, end))
2652 const auto &chunk = *it;
2654 if (!terminated && chunk == terminator)
2657 } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag)
2659 if (!ParseLong(it, end))
2663 } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag)
2665 if (!ParseShort(it, end))
2669 } else if (!terminated && !commands.empty())
2671 auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; });
2672 if (itCommand == commands.end())
2674 const std::string errorMessage("Unknown command: " + chunk);
2675 #ifndef ARGS_NOEXCEPT
2676 throw ParseError(errorMessage);
2678 error = Error::Parse;
2679 errorMsg = errorMessage;
2684 SelectCommand(*itCommand);
2686 if (const auto &coroutine = GetCoroutine())
2689 RaiiSubparser coro(*this, std::vector<std::string>(it, end));
2690 coroutine(coro.Parser());
2691 #ifdef ARGS_NOEXCEPT
2693 if (error != Error::None)
2698 if (!coro.Parser().IsParsed())
2700 error = Error::Usage;
2704 if (!coro.Parser().IsParsed())
2706 throw UsageError("Subparser::Parse was not called");
2713 commands = GetCommands();
2716 auto pos = GetNextPositional();
2719 pos->ParseValue(chunk);
2727 const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk);
2728 #ifndef ARGS_NOEXCEPT
2729 throw ParseError(errorMessage);
2731 error = Error::Parse;
2732 errorMsg = errorMessage;
2738 if (!readCompletion && completion != nullptr && completion->Matched())
2740 #ifdef ARGS_NOEXCEPT
2741 error = Error::Completion;
2743 readCompletion = true;
2745 const auto argsLeft = static_cast<size_t>(std::distance(it, end));
2746 if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft)
2748 #ifndef ARGS_NOEXCEPT
2749 throw Completion("");
2753 std::vector<std::string> curArgs(++it, end);
2754 curArgs.resize(completion->cword);
2756 if (completion->syntax == "bash")
2758 // bash tokenizes --flag=value as --flag=value
2759 for (size_t idx = 0; idx < curArgs.size(); )
2761 if (idx > 0 && curArgs[idx] == "=")
2763 curArgs[idx - 1] += "=";
2764 // Avoid warnings from -Wsign-conversion
2765 const auto signedIdx = static_cast<std::ptrdiff_t>(idx);
2766 if (idx + 1 < curArgs.size())
2768 curArgs[idx - 1] += curArgs[idx + 1];
2769 curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2);
2772 curArgs.erase(curArgs.begin() + signedIdx);
2781 #ifndef ARGS_NOEXCEPT
2784 Parse(curArgs.begin(), curArgs.end());
2785 throw Completion("");
2787 catch (Completion &)
2791 catch (args::Error&)
2793 throw Completion("");
2796 return Parse(curArgs.begin(), curArgs.end());
2801 Validate(shortprefix, longprefix);
2806 HelpParams helpParams;
2808 ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string())
2810 Description(description_);
2816 SetArgumentSeparations(true, true, true, true);
2820 void AddCompletion(CompletionFlag &completionFlag)
2822 completion = &completionFlag;
2823 Add(completionFlag);
2826 /** The program name for help generation
2828 const std::string &Prog() const
2829 { return helpParams.programName; }
2830 /** The program name for help generation
2832 void Prog(const std::string &prog_)
2833 { this->helpParams.programName = prog_; }
2835 /** The prefix for long flags
2837 const std::string &LongPrefix() const
2838 { return longprefix; }
2839 /** The prefix for long flags
2841 void LongPrefix(const std::string &longprefix_)
2843 this->longprefix = longprefix_;
2844 this->helpParams.longPrefix = longprefix_;
2847 /** The prefix for short flags
2849 const std::string &ShortPrefix() const
2850 { return shortprefix; }
2851 /** The prefix for short flags
2853 void ShortPrefix(const std::string &shortprefix_)
2855 this->shortprefix = shortprefix_;
2856 this->helpParams.shortPrefix = shortprefix_;
2859 /** The separator for long flags
2861 const std::string &LongSeparator() const
2862 { return longseparator; }
2863 /** The separator for long flags
2865 void LongSeparator(const std::string &longseparator_)
2867 if (longseparator_.empty())
2869 const std::string errorMessage("longseparator can not be set to empty");
2870 #ifdef ARGS_NOEXCEPT
2871 error = Error::Usage;
2872 errorMsg = errorMessage;
2874 throw UsageError(errorMessage);
2878 this->longseparator = longseparator_;
2879 this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " ";
2883 /** The terminator that forcibly separates flags from positionals
2885 const std::string &Terminator() const
2886 { return terminator; }
2887 /** The terminator that forcibly separates flags from positionals
2889 void Terminator(const std::string &terminator_)
2890 { this->terminator = terminator_; }
2892 /** Get the current argument separation parameters.
2894 * See SetArgumentSeparations for details on what each one means.
2896 void GetArgumentSeparations(
2897 bool &allowJoinedShortValue_,
2898 bool &allowJoinedLongValue_,
2899 bool &allowSeparateShortValue_,
2900 bool &allowSeparateLongValue_) const
2902 allowJoinedShortValue_ = this->allowJoinedShortValue;
2903 allowJoinedLongValue_ = this->allowJoinedLongValue;
2904 allowSeparateShortValue_ = this->allowSeparateShortValue;
2905 allowSeparateLongValue_ = this->allowSeparateLongValue;
2908 /** Change allowed option separation.
2910 * \param allowJoinedShortValue_ Allow a short flag that accepts an argument to be passed its argument immediately next to it (ie. in the same argv field)
2911 * \param allowJoinedLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by the longseparator (ie. in the same argv field)
2912 * \param allowSeparateShortValue_ Allow a short flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field)
2913 * \param allowSeparateLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field)
2915 void SetArgumentSeparations(
2916 const bool allowJoinedShortValue_,
2917 const bool allowJoinedLongValue_,
2918 const bool allowSeparateShortValue_,
2919 const bool allowSeparateLongValue_)
2921 this->allowJoinedShortValue = allowJoinedShortValue_;
2922 this->allowJoinedLongValue = allowJoinedLongValue_;
2923 this->allowSeparateShortValue = allowSeparateShortValue_;
2924 this->allowSeparateLongValue = allowSeparateLongValue_;
2926 this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " ";
2927 this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " ";
2930 /** Pass the help menu into an ostream
2932 void Help(std::ostream &help_) const
2934 auto &command = SelectedCommand();
2935 const auto &commandDescription = command.Description().empty() ? command.Help() : command.Description();
2936 const auto description_text = Wrap(commandDescription, helpParams.width - helpParams.descriptionindent);
2937 const auto epilog_text = Wrap(command.Epilog(), helpParams.width - helpParams.descriptionindent);
2939 const bool hasoptions = command.HasFlag();
2940 const bool hasarguments = command.HasPositional();
2942 std::vector<std::string> prognameline;
2943 prognameline.push_back(helpParams.usageString);
2944 prognameline.push_back(Prog());
2945 auto commandProgLine = command.GetProgramLine(helpParams);
2946 prognameline.insert(prognameline.end(), commandProgLine.begin(), commandProgLine.end());
2948 const auto proglines = Wrap(prognameline.begin(), prognameline.end(),
2949 helpParams.width - (helpParams.progindent + helpParams.progtailindent),
2950 helpParams.width - helpParams.progindent);
2951 auto progit = std::begin(proglines);
2952 if (progit != std::end(proglines))
2954 help_ << std::string(helpParams.progindent, ' ') << *progit << '\n';
2957 for (; progit != std::end(proglines); ++progit)
2959 help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n';
2964 if (!description_text.empty())
2966 for (const auto &line: description_text)
2968 help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
2973 bool lastDescriptionIsNewline = false;
2975 if (!helpParams.optionsString.empty())
2977 help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n";
2980 for (const auto &desc: command.GetDescription(helpParams, 0))
2982 lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty();
2983 const auto groupindent = std::get<2>(desc) * helpParams.eachgroupindent;
2984 const auto flags = Wrap(std::get<0>(desc), helpParams.width - (helpParams.flagindent + helpParams.helpindent + helpParams.gutter));
2985 const auto info = Wrap(std::get<1>(desc), helpParams.width - (helpParams.helpindent + groupindent));
2987 std::string::size_type flagssize = 0;
2988 for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit)
2990 if (flagsit != std::begin(flags))
2994 help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit;
2995 flagssize = Glyphs(*flagsit);
2998 auto infoit = std::begin(info);
2999 // groupindent is on both sides of this inequality, and therefore can be removed
3000 if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription)
3005 // groupindent is on both sides of the minus sign, and therefore doesn't actually need to be in here
3006 help_ << std::string(helpParams.helpindent - (helpParams.flagindent + flagssize), ' ') << *infoit << '\n';
3009 for (; infoit != std::end(info); ++infoit)
3011 help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n';
3014 if (hasoptions && hasarguments && helpParams.showTerminator)
3016 lastDescriptionIsNewline = false;
3017 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))
3019 help_ << std::string(helpParams.flagindent, ' ') << item << '\n';
3023 if (!lastDescriptionIsNewline)
3028 for (const auto &line: epilog_text)
3030 help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
3034 /** Generate a help menu as a string.
3036 * \return the help text as a single string
3038 std::string Help() const
3040 std::ostringstream help_;
3045 virtual void Reset() noexcept override
3049 readCompletion = false;
3052 /** Parse all arguments.
3054 * \param begin an iterator to the beginning of the argument list
3055 * \param end an iterator to the past-the-end element of the argument list
3056 * \return the iterator after the last parsed value. Only useful for kick-out
3058 template <typename It>
3059 It ParseArgs(It begin, It end)
3061 // Reset all Matched statuses and errors
3063 #ifdef ARGS_NOEXCEPT
3065 if (error != Error::None)
3070 return Parse(begin, end);
3073 /** Parse all arguments.
3075 * \param args an iterable of the arguments
3076 * \return the iterator after the last parsed value. Only useful for kick-out
3078 template <typename T>
3079 auto ParseArgs(const T &args) -> decltype(std::begin(args))
3081 return ParseArgs(std::begin(args), std::end(args));
3084 /** Convenience function to parse the CLI from argc and argv
3086 * Just assigns the program name and vectorizes arguments for passing into ParseArgs()
3088 * \return whether or not all arguments were parsed. This works for detecting kick-out, but is generally useless as it can't do anything with it.
3090 bool ParseCLI(const int argc, const char * const * argv)
3096 const std::vector<std::string> args(argv + 1, argv + argc);
3097 return ParseArgs(args) == std::end(args);
3100 template <typename T>
3101 bool ParseCLI(const T &args)
3103 return ParseArgs(args) == std::end(args);
3107 inline Command::RaiiSubparser::RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_)
3108 : command(parser_.SelectedCommand()), parser(std::move(args_), parser_, command, parser_.helpParams), oldSubparser(command.subparser)
3110 command.subparser = &parser;
3113 inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams ¶ms_): command(command_), parser(command, params_), oldSubparser(command.subparser)
3115 command.subparser = &parser;
3118 inline void Subparser::Parse()
3122 command.subparserDescription = GetDescription(helpParams, 0);
3123 command.subparserHasFlag = HasFlag();
3124 command.subparserHasPositional = HasPositional();
3125 command.subparserHasCommand = HasCommand();
3126 command.subparserProgramLine = GetProgramLine(helpParams);
3127 if (parser == nullptr)
3129 #ifndef ARGS_NOEXCEPT
3130 throw args::SubparserError();
3132 error = Error::Subparser;
3137 auto it = parser->Parse(args.begin(), args.end());
3138 command.Validate(parser->ShortPrefix(), parser->LongPrefix());
3139 kicked.assign(it, args.end());
3141 #ifdef ARGS_NOEXCEPT
3142 command.subparserError = GetError();
3146 inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser)
3152 /** Boolean argument matcher
3154 class Flag : public FlagBase
3157 Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_)
3162 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)
3168 /** Get whether this was matched
3175 virtual Nargs NumberOfArguments() const noexcept override
3180 virtual void ParseValue(const std::vector<std::string>&) override
3187 * Works like a regular flag, but throws an instance of Help when it is matched
3189 class HelpFlag : public Flag
3192 HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {}
3194 virtual ~HelpFlag() {}
3196 virtual void ParseValue(const std::vector<std::string> &)
3198 #ifdef ARGS_NOEXCEPT
3199 error = Error::Help;
3206 /** Get whether this was matched
3208 bool Get() const noexcept
3214 /** A flag class that simply counts the number of times it's matched
3216 class CounterFlag : public Flag
3219 const int startcount;
3223 CounterFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const int startcount_ = 0, Options options_ = {}):
3224 Flag(group_, name_, help_, std::move(matcher_), options_), startcount(startcount_), count(startcount_) {}
3226 virtual ~CounterFlag() {}
3228 virtual FlagBase *Match(const EitherFlag &arg) override
3230 auto me = FlagBase::Match(arg);
3245 int &operator *() noexcept {
3249 const int &operator *() const noexcept {
3253 virtual void Reset() noexcept override
3260 /** A flag class that calls a function when it's matched
3262 class ActionFlag : public FlagBase
3265 std::function<void(const std::vector<std::string> &)> action;
3269 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_ = {}):
3270 FlagBase(name_, help_, std::move(matcher_), options_), action(std::move(action_)), nargs(nargs_)
3275 ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void(const std::string &)> action_, Options options_ = {}):
3276 FlagBase(name_, help_, std::move(matcher_), options_), nargs(1)
3279 action = [action_](const std::vector<std::string> &a) { return action_(a.at(0)); };
3282 ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void()> action_, Options options_ = {}):
3283 FlagBase(name_, help_, std::move(matcher_), options_), nargs(0)
3286 action = [action_](const std::vector<std::string> &) { return action_(); };
3289 virtual Nargs NumberOfArguments() const noexcept override
3292 virtual void ParseValue(const std::vector<std::string> &value) override
3296 /** A default Reader class for argument classes
3298 * If destination type is assignable to std::string it uses an assignment to std::string.
3299 * Otherwise ValueReader simply uses a std::istringstream to read into the destination type, and
3300 * raises a ParseError if there are any characters left.
3304 template <typename T>
3305 typename std::enable_if<!std::is_assignable<T, std::string>::value, bool>::type
3306 operator ()(const std::string &name, const std::string &value, T &destination)
3308 std::istringstream ss(value);
3309 bool failed = !(ss >> destination);
3316 if (ss.rdbuf()->in_avail() > 0 || failed)
3318 #ifdef ARGS_NOEXCEPT
3322 std::ostringstream problem;
3323 problem << "Argument '" << name << "' received invalid value type '" << value << "'";
3324 throw ParseError(problem.str());
3330 template <typename T>
3331 typename std::enable_if<std::is_assignable<T, std::string>::value, bool>::type
3332 operator()(const std::string &, const std::string &value, T &destination)
3334 destination = value;
3339 /** An argument-accepting flag class
3341 * \tparam T the type to extract the argument as
3342 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
3346 typename Reader = ValueReader>
3347 class ValueFlag : public ValueFlagBase
3353 virtual std::string GetDefaultString(const HelpParams&) const override
3355 return detail::ToString(defaultValue);
3363 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_)
3368 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)
3372 ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): ValueFlag(group_, name_, help_, std::move(matcher_), T(), options_)
3376 virtual ~ValueFlag() {}
3378 virtual void ParseValue(const std::vector<std::string> &values_) override
3380 const std::string &value_ = values_.at(0);
3382 #ifdef ARGS_NOEXCEPT
3383 if (!reader(name, value_, this->value))
3385 error = Error::Parse;
3388 reader(name, value_, this->value);
3392 virtual void Reset() noexcept override
3394 ValueFlagBase::Reset();
3395 value = defaultValue;
3407 T &operator *() noexcept
3414 const T &operator *() const noexcept
3421 T *operator ->() noexcept
3428 const T *operator ->() const noexcept
3433 /** Get the default value
3435 const T &GetDefault() noexcept
3437 return defaultValue;
3441 /** An optional argument-accepting flag class
3443 * \tparam T the type to extract the argument as
3444 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
3448 typename Reader = ValueReader>
3449 class ImplicitValueFlag : public ValueFlag<T, Reader>
3456 ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {})
3457 : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_)
3461 ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {})
3462 : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_)
3466 ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_)
3467 : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue()
3471 virtual ~ImplicitValueFlag() {}
3473 virtual Nargs NumberOfArguments() const noexcept override
3478 virtual void ParseValue(const std::vector<std::string> &value_) override
3482 this->value = implicitValue;
3485 ValueFlag<T, Reader>::ParseValue(value_);
3490 /** A variadic arguments accepting flag class
3492 * \tparam T the type to extract the argument as
3493 * \tparam List the list type that houses the values
3494 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
3498 template <typename...> class List = detail::vector,
3499 typename Reader = ValueReader>
3500 class NargsValueFlag : public FlagBase
3505 const List<T> defaultValues;
3511 typedef List<T> Container;
3512 typedef T value_type;
3513 typedef typename Container::allocator_type allocator_type;
3514 typedef typename Container::pointer pointer;
3515 typedef typename Container::const_pointer const_pointer;
3516 typedef T& reference;
3517 typedef const T& const_reference;
3518 typedef typename Container::size_type size_type;
3519 typedef typename Container::difference_type difference_type;
3520 typedef typename Container::iterator iterator;
3521 typedef typename Container::const_iterator const_iterator;
3522 typedef std::reverse_iterator<iterator> reverse_iterator;
3523 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3525 NargsValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, const List<T> &defaultValues_ = {}, Options options_ = {})
3526 : FlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_),nargs(nargs_)
3531 virtual ~NargsValueFlag() {}
3533 virtual Nargs NumberOfArguments() const noexcept override
3538 virtual void ParseValue(const std::vector<std::string> &values_) override
3542 for (const std::string &value : values_)
3545 #ifdef ARGS_NOEXCEPT
3546 if (!reader(name, value, v))
3548 error = Error::Parse;
3551 reader(name, value, v);
3553 values.insert(std::end(values), v);
3557 List<T> &Get() noexcept
3564 List<T> &operator *() noexcept
3571 const List<T> &operator *() const noexcept
3578 List<T> *operator ->() noexcept
3585 const List<T> *operator ->() const noexcept
3590 iterator begin() noexcept
3592 return values.begin();
3595 const_iterator begin() const noexcept
3597 return values.begin();
3600 const_iterator cbegin() const noexcept
3602 return values.cbegin();
3605 iterator end() noexcept
3607 return values.end();
3610 const_iterator end() const noexcept
3612 return values.end();
3615 const_iterator cend() const noexcept
3617 return values.cend();
3620 virtual void Reset() noexcept override
3623 values = defaultValues;
3626 virtual FlagBase *Match(const EitherFlag &arg) override
3628 const bool wasMatched = Matched();
3629 auto me = FlagBase::Match(arg);
3630 if (me && !wasMatched)
3638 /** An argument-accepting flag class that pushes the found values into a list
3640 * \tparam T the type to extract the argument as
3641 * \tparam List the list type that houses the values
3642 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
3646 template <typename...> class List = detail::vector,
3647 typename Reader = ValueReader>
3648 class ValueFlagList : public ValueFlagBase
3651 using Container = List<T>;
3653 const Container defaultValues;
3658 typedef T value_type;
3659 typedef typename Container::allocator_type allocator_type;
3660 typedef typename Container::pointer pointer;
3661 typedef typename Container::const_pointer const_pointer;
3662 typedef T& reference;
3663 typedef const T& const_reference;
3664 typedef typename Container::size_type size_type;
3665 typedef typename Container::difference_type difference_type;
3666 typedef typename Container::iterator iterator;
3667 typedef typename Container::const_iterator const_iterator;
3668 typedef std::reverse_iterator<iterator> reverse_iterator;
3669 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3671 ValueFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Container &defaultValues_ = Container(), Options options_ = {}):
3672 ValueFlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_)
3677 virtual ~ValueFlagList() {}
3679 virtual void ParseValue(const std::vector<std::string> &values_) override
3681 const std::string &value_ = values_.at(0);
3684 #ifdef ARGS_NOEXCEPT
3685 if (!reader(name, value_, v))
3687 error = Error::Parse;
3690 reader(name, value_, v);
3692 values.insert(std::end(values), v);
3697 Container &Get() noexcept
3704 Container &operator *() noexcept
3711 const Container &operator *() const noexcept
3718 Container *operator ->() noexcept
3725 const Container *operator ->() const noexcept
3730 virtual std::string Name() const override
3732 return name + std::string("...");
3735 virtual void Reset() noexcept override
3737 ValueFlagBase::Reset();
3738 values = defaultValues;
3741 virtual FlagBase *Match(const EitherFlag &arg) override
3743 const bool wasMatched = Matched();
3744 auto me = FlagBase::Match(arg);
3745 if (me && !wasMatched)
3752 iterator begin() noexcept
3754 return values.begin();
3757 const_iterator begin() const noexcept
3759 return values.begin();
3762 const_iterator cbegin() const noexcept
3764 return values.cbegin();
3767 iterator end() noexcept
3769 return values.end();
3772 const_iterator end() const noexcept
3774 return values.end();
3777 const_iterator cend() const noexcept
3779 return values.cend();
3783 /** A mapping value flag class
3785 * \tparam K the type to extract the argument as
3786 * \tparam T the type to store the result as
3787 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
3788 * \tparam Map The Map type. Should operate like std::map or std::unordered_map
3793 typename Reader = ValueReader,
3794 template <typename...> class Map = detail::unordered_map>
3795 class MapFlag : public ValueFlagBase
3798 const Map<K, T> map;
3800 const T defaultValue;
3804 virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3806 return detail::MapKeysToStrings(map);
3811 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_)
3816 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)
3820 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_)
3824 virtual ~MapFlag() {}
3826 virtual void ParseValue(const std::vector<std::string> &values_) override
3828 const std::string &value_ = values_.at(0);
3831 #ifdef ARGS_NOEXCEPT
3832 if (!reader(name, value_, key))
3834 error = Error::Parse;
3837 reader(name, value_, key);
3839 auto it = map.find(key);
3840 if (it == std::end(map))
3842 std::ostringstream problem;
3843 problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3844 #ifdef ARGS_NOEXCEPT
3846 errorMsg = problem.str();
3848 throw MapError(problem.str());
3852 this->value = it->second;
3865 T &operator *() noexcept
3872 const T &operator *() const noexcept
3879 T *operator ->() noexcept
3886 const T *operator ->() const noexcept
3891 virtual void Reset() noexcept override
3893 ValueFlagBase::Reset();
3894 value = defaultValue;
3898 /** A mapping value flag list class
3900 * \tparam K the type to extract the argument as
3901 * \tparam T the type to store the result as
3902 * \tparam List the list type that houses the values
3903 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
3904 * \tparam Map The Map type. Should operate like std::map or std::unordered_map
3909 template <typename...> class List = detail::vector,
3910 typename Reader = ValueReader,
3911 template <typename...> class Map = detail::unordered_map>
3912 class MapFlagList : public ValueFlagBase
3915 using Container = List<T>;
3916 const Map<K, T> map;
3918 const Container defaultValues;
3922 virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3924 return detail::MapKeysToStrings(map);
3928 typedef T value_type;
3929 typedef typename Container::allocator_type allocator_type;
3930 typedef typename Container::pointer pointer;
3931 typedef typename Container::const_pointer const_pointer;
3932 typedef T& reference;
3933 typedef const T& const_reference;
3934 typedef typename Container::size_type size_type;
3935 typedef typename Container::difference_type difference_type;
3936 typedef typename Container::iterator iterator;
3937 typedef typename Container::const_iterator const_iterator;
3938 typedef std::reverse_iterator<iterator> reverse_iterator;
3939 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3941 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_)
3946 virtual ~MapFlagList() {}
3948 virtual void ParseValue(const std::vector<std::string> &values_) override
3950 const std::string &value = values_.at(0);
3953 #ifdef ARGS_NOEXCEPT
3954 if (!reader(name, value, key))
3956 error = Error::Parse;
3959 reader(name, value, key);
3961 auto it = map.find(key);
3962 if (it == std::end(map))
3964 std::ostringstream problem;
3965 problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3966 #ifdef ARGS_NOEXCEPT
3968 errorMsg = problem.str();
3970 throw MapError(problem.str());
3974 this->values.emplace_back(it->second);
3980 Container &Get() noexcept
3987 Container &operator *() noexcept
3994 const Container &operator *() const noexcept
4001 Container *operator ->() noexcept
4008 const Container *operator ->() const noexcept
4013 virtual std::string Name() const override
4015 return name + std::string("...");
4018 virtual void Reset() noexcept override
4020 ValueFlagBase::Reset();
4021 values = defaultValues;
4024 virtual FlagBase *Match(const EitherFlag &arg) override
4026 const bool wasMatched = Matched();
4027 auto me = FlagBase::Match(arg);
4028 if (me && !wasMatched)
4035 iterator begin() noexcept
4037 return values.begin();
4040 const_iterator begin() const noexcept
4042 return values.begin();
4045 const_iterator cbegin() const noexcept
4047 return values.cbegin();
4050 iterator end() noexcept
4052 return values.end();
4055 const_iterator end() const noexcept
4057 return values.end();
4060 const_iterator cend() const noexcept
4062 return values.cend();
4066 /** A positional argument class
4068 * \tparam T the type to extract the argument as
4069 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
4073 typename Reader = ValueReader>
4074 class Positional : public PositionalBase
4078 const T defaultValue;
4081 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_)
4086 Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_)
4090 virtual ~Positional() {}
4092 virtual void ParseValue(const std::string &value_) override
4094 #ifdef ARGS_NOEXCEPT
4095 if (!reader(name, value_, this->value))
4097 error = Error::Parse;
4100 reader(name, value_, this->value);
4115 T &operator *() noexcept
4122 const T &operator *() const noexcept
4129 T *operator ->() noexcept
4136 const T *operator ->() const noexcept
4141 virtual void Reset() noexcept override
4143 PositionalBase::Reset();
4144 value = defaultValue;
4148 /** A positional argument class that pushes the found values into a list
4150 * \tparam T the type to extract the argument as
4151 * \tparam List the list type that houses the values
4152 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
4156 template <typename...> class List = detail::vector,
4157 typename Reader = ValueReader>
4158 class PositionalList : public PositionalBase
4161 using Container = List<T>;
4163 const Container defaultValues;
4167 typedef T value_type;
4168 typedef typename Container::allocator_type allocator_type;
4169 typedef typename Container::pointer pointer;
4170 typedef typename Container::const_pointer const_pointer;
4171 typedef T& reference;
4172 typedef const T& const_reference;
4173 typedef typename Container::size_type size_type;
4174 typedef typename Container::difference_type difference_type;
4175 typedef typename Container::iterator iterator;
4176 typedef typename Container::const_iterator const_iterator;
4177 typedef std::reverse_iterator<iterator> reverse_iterator;
4178 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4180 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_)
4185 PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_)
4189 virtual ~PositionalList() {}
4191 virtual void ParseValue(const std::string &value_) override
4194 #ifdef ARGS_NOEXCEPT
4195 if (!reader(name, value_, v))
4197 error = Error::Parse;
4200 reader(name, value_, v);
4202 values.insert(std::end(values), v);
4206 virtual std::string Name() const override
4208 return name + std::string("...");
4213 Container &Get() noexcept
4220 Container &operator *() noexcept
4227 const Container &operator *() const noexcept
4234 Container *operator ->() noexcept
4241 const Container *operator ->() const noexcept
4246 virtual void Reset() noexcept override
4248 PositionalBase::Reset();
4249 values = defaultValues;
4252 virtual PositionalBase *GetNextPositional() override
4254 const bool wasMatched = Matched();
4255 auto me = PositionalBase::GetNextPositional();
4256 if (me && !wasMatched)
4263 iterator begin() noexcept
4265 return values.begin();
4268 const_iterator begin() const noexcept
4270 return values.begin();
4273 const_iterator cbegin() const noexcept
4275 return values.cbegin();
4278 iterator end() noexcept
4280 return values.end();
4283 const_iterator end() const noexcept
4285 return values.end();
4288 const_iterator cend() const noexcept
4290 return values.cend();
4294 /** A positional argument mapping class
4296 * \tparam K the type to extract the argument as
4297 * \tparam T the type to store the result as
4298 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
4299 * \tparam Map The Map type. Should operate like std::map or std::unordered_map
4304 typename Reader = ValueReader,
4305 template <typename...> class Map = detail::unordered_map>
4306 class MapPositional : public PositionalBase
4309 const Map<K, T> map;
4311 const T defaultValue;
4315 virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4317 return detail::MapKeysToStrings(map);
4322 MapPositional(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const T &defaultValue_ = T(), Options options_ = {}):
4323 PositionalBase(name_, help_, options_), map(map_), value(defaultValue_), defaultValue(defaultValue_)
4328 virtual ~MapPositional() {}
4330 virtual void ParseValue(const std::string &value_) override
4333 #ifdef ARGS_NOEXCEPT
4334 if (!reader(name, value_, key))
4336 error = Error::Parse;
4339 reader(name, value_, key);
4341 auto it = map.find(key);
4342 if (it == std::end(map))
4344 std::ostringstream problem;
4345 problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4346 #ifdef ARGS_NOEXCEPT
4348 errorMsg = problem.str();
4350 throw MapError(problem.str());
4354 this->value = it->second;
4369 T &operator *() noexcept
4376 const T &operator *() const noexcept
4383 T *operator ->() noexcept
4390 const T *operator ->() const noexcept
4395 virtual void Reset() noexcept override
4397 PositionalBase::Reset();
4398 value = defaultValue;
4402 /** A positional argument mapping list class
4404 * \tparam K the type to extract the argument as
4405 * \tparam T the type to store the result as
4406 * \tparam List the list type that houses the values
4407 * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined)
4408 * \tparam Map The Map type. Should operate like std::map or std::unordered_map
4413 template <typename...> class List = detail::vector,
4414 typename Reader = ValueReader,
4415 template <typename...> class Map = detail::unordered_map>
4416 class MapPositionalList : public PositionalBase
4419 using Container = List<T>;
4421 const Map<K, T> map;
4423 const Container defaultValues;
4427 virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4429 return detail::MapKeysToStrings(map);
4433 typedef T value_type;
4434 typedef typename Container::allocator_type allocator_type;
4435 typedef typename Container::pointer pointer;
4436 typedef typename Container::const_pointer const_pointer;
4437 typedef T& reference;
4438 typedef const T& const_reference;
4439 typedef typename Container::size_type size_type;
4440 typedef typename Container::difference_type difference_type;
4441 typedef typename Container::iterator iterator;
4442 typedef typename Container::const_iterator const_iterator;
4443 typedef std::reverse_iterator<iterator> reverse_iterator;
4444 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4446 MapPositionalList(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const Container &defaultValues_ = Container(), Options options_ = {}):
4447 PositionalBase(name_, help_, options_), map(map_), values(defaultValues_), defaultValues(defaultValues_)
4452 virtual ~MapPositionalList() {}
4454 virtual void ParseValue(const std::string &value_) override
4457 #ifdef ARGS_NOEXCEPT
4458 if (!reader(name, value_, key))
4460 error = Error::Parse;
4463 reader(name, value_, key);
4465 auto it = map.find(key);
4466 if (it == std::end(map))
4468 std::ostringstream problem;
4469 problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4470 #ifdef ARGS_NOEXCEPT
4472 errorMsg = problem.str();
4474 throw MapError(problem.str());
4478 this->values.emplace_back(it->second);
4485 Container &Get() noexcept
4492 Container &operator *() noexcept
4499 const Container &operator *() const noexcept
4506 Container *operator ->() noexcept
4513 const Container *operator ->() const noexcept
4518 virtual std::string Name() const override
4520 return name + std::string("...");
4523 virtual void Reset() noexcept override
4525 PositionalBase::Reset();
4526 values = defaultValues;
4529 virtual PositionalBase *GetNextPositional() override
4531 const bool wasMatched = Matched();
4532 auto me = PositionalBase::GetNextPositional();
4533 if (me && !wasMatched)
4540 iterator begin() noexcept
4542 return values.begin();
4545 const_iterator begin() const noexcept
4547 return values.begin();
4550 const_iterator cbegin() const noexcept
4552 return values.cbegin();
4555 iterator end() noexcept
4557 return values.end();
4560 const_iterator end() const noexcept
4562 return values.end();
4565 const_iterator cend() const noexcept
4567 return values.cend();