MatN work for versatile appimage creation for all types of os
[goodguy/cinelerra.git] / cinelerra-5.1 / tools / makeappimagetool / includes / args.hxx
1 /* A simple header-only C++ argument parser library.
2  *
3  * https://github.com/Taywee/args
4  *
5  * Copyright (c) 2016-2021 Taylor C. Richberger <taywee@gmx.com> and Pavel
6  * Belikov
7  * 
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to
10  * deal in the Software without restriction, including without limitation the
11  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12  * sell copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  * 
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24  * IN THE SOFTWARE.
25  */
26
27 /** \file args.hxx
28  * \brief this single-header lets you use all of the args functionality
29  *
30  * The important stuff is done inside the args namespace
31  */
32
33 #ifndef ARGS_HXX
34 #define ARGS_HXX
35
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
40
41 #include <algorithm>
42 #include <iterator>
43 #include <exception>
44 #include <functional>
45 #include <sstream>
46 #include <string>
47 #include <tuple>
48 #include <vector>
49 #include <unordered_map>
50 #include <unordered_set>
51 #include <type_traits>
52 #include <cstddef>
53 #include <cctype>
54 #include <iostream>
55
56 #if defined(_MSC_VER) && _MSC_VER <= 1800
57 #define noexcept
58 #endif
59
60 #ifdef ARGS_TESTNAMESPACE
61 namespace argstest
62 {
63 #else
64
65 /** \namespace args
66  * \brief contains all the functionality of the args library
67  */
68 namespace args
69 {
70 #endif
71     /** Getter to grab the value from the argument type.
72      *
73      * If the Get() function of the type returns a reference, so does this, and
74      * the value will be modifiable.
75      */
76     template <typename Option>
77     auto get(Option &option_) -> decltype(option_.Get())
78     {
79         return option_.Get();
80     }
81
82     /** (INTERNAL) Count UTF-8 glyphs
83      *
84      * This is not reliable, and will fail for combinatory glyphs, but it's
85      * good enough here for now.
86      *
87      * \param string The string to count glyphs from
88      * \return The UTF-8 glyphs in the string
89      */
90     inline std::string::size_type Glyphs(const std::string &string_)
91     {
92         std::string::size_type length = 0;
93         for (const char c: string_)
94         {
95             if ((c & 0xc0) != 0x80)
96             {
97                 ++length;
98             }
99         }
100         return length;
101     }
102
103     /** (INTERNAL) Wrap a vector of words into a vector of lines
104      *
105      * Empty words are skipped. Word "\n" forces wrapping.
106      *
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
113      */
114     template <typename It>
115     inline std::vector<std::string> Wrap(It begin,
116                                          It end,
117                                          const std::string::size_type width,
118                                          std::string::size_type firstlinewidth = 0,
119                                          std::string::size_type firstlineindent = 0)
120     {
121         std::vector<std::string> output;
122         std::string line(firstlineindent, ' ');
123         bool empty = true;
124
125         if (firstlinewidth == 0)
126         {
127             firstlinewidth = width;
128         }
129
130         auto currentwidth = firstlinewidth;
131
132         for (auto it = begin; it != end; ++it)
133         {
134             if (it->empty())
135             {
136                 continue;
137             }
138
139             if (*it == "\n")
140             {
141                 if (!empty)
142                 {
143                     output.push_back(line);
144                     line.clear();
145                     empty = true;
146                     currentwidth = width;
147                 }
148
149                 continue;
150             }
151
152             auto itemsize = Glyphs(*it);
153             if ((line.length() + 1 + itemsize) > currentwidth)
154             {
155                 if (!empty)
156                 {
157                     output.push_back(line);
158                     line.clear();
159                     empty = true;
160                     currentwidth = width;
161                 }
162             }
163
164             if (itemsize > 0)
165             {
166                 if (!empty)
167                 {
168                     line += ' ';
169                 }
170
171                 line += *it;
172                 empty = false;
173             }
174         }
175
176         if (!empty)
177         {
178             output.push_back(line);
179         }
180
181         return output;
182     }
183
184     namespace detail
185     {
186         template <typename T>
187         std::string Join(const T& array, const std::string &delimiter)
188         {
189             std::string res;
190             for (auto &element : array)
191             {
192                 if (!res.empty())
193                 {
194                     res += delimiter;
195                 }
196
197                 res += element;
198             }
199
200             return res;
201         }
202     }
203
204     /** (INTERNAL) Wrap a string into a vector of lines
205      *
206      * This is quick and hacky, but works well enough.  You can specify a
207      * different width for the first line
208      *
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
212      */
213     inline std::vector<std::string> Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0)
214     {
215         // Preserve existing line breaks
216         const auto newlineloc = in.find('\n');
217         if (newlineloc != in.npos)
218         {
219             auto first = Wrap(std::string(in, 0, newlineloc), width);
220             auto second = Wrap(std::string(in, newlineloc + 1), width);
221             first.insert(
222                 std::end(first),
223                 std::make_move_iterator(std::begin(second)),
224                 std::make_move_iterator(std::end(second)));
225             return first;
226         }
227
228         std::istringstream stream(in);
229         std::string::size_type indent = 0;
230
231         for (auto c : in)
232         {
233             if (!std::isspace(static_cast<unsigned char>(c)))
234             {
235                 break;
236             }
237             ++indent;
238         }
239
240         return Wrap(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>(),
241                     width, firstlinewidth, indent);
242     }
243
244 #ifdef ARGS_NOEXCEPT
245     /// Error class, for when ARGS_NOEXCEPT is defined
246     enum class Error
247     {
248         None,
249         Usage,
250         Parse,
251         Validation,
252         Required,
253         Map,
254         Extra,
255         Help,
256         Subparser,
257         Completion,
258     };
259 #else
260     /** Base error class
261      */
262     class Error : public std::runtime_error
263     {
264         public:
265             Error(const std::string &problem) : std::runtime_error(problem) {}
266             virtual ~Error() {}
267     };
268
269     /** Errors that occur during usage
270      */
271     class UsageError : public Error
272     {
273         public:
274             UsageError(const std::string &problem) : Error(problem) {}
275             virtual ~UsageError() {}
276     };
277
278     /** Errors that occur during regular parsing
279      */
280     class ParseError : public Error
281     {
282         public:
283             ParseError(const std::string &problem) : Error(problem) {}
284             virtual ~ParseError() {}
285     };
286
287     /** Errors that are detected from group validation after parsing finishes
288      */
289     class ValidationError : public Error
290     {
291         public:
292             ValidationError(const std::string &problem) : Error(problem) {}
293             virtual ~ValidationError() {}
294     };
295
296     /** Errors that when a required flag is omitted
297      */
298     class RequiredError : public ValidationError
299     {
300         public:
301             RequiredError(const std::string &problem) : ValidationError(problem) {}
302             virtual ~RequiredError() {}
303     };
304
305     /** Errors in map lookups
306      */
307     class MapError : public ParseError
308     {
309         public:
310             MapError(const std::string &problem) : ParseError(problem) {}
311             virtual ~MapError() {}
312     };
313
314     /** Error that occurs when a singular flag is specified multiple times
315      */
316     class ExtraError : public ParseError
317     {
318         public:
319             ExtraError(const std::string &problem) : ParseError(problem) {}
320             virtual ~ExtraError() {}
321     };
322
323     /** An exception that indicates that the user has requested help
324      */
325     class Help : public Error
326     {
327         public:
328             Help(const std::string &flag) : Error(flag) {}
329             virtual ~Help() {}
330     };
331
332     /** (INTERNAL) An exception that emulates coroutine-like control flow for subparsers.
333      */
334     class SubparserError : public Error
335     {
336         public:
337             SubparserError() : Error("") {}
338             virtual ~SubparserError() {}
339     };
340
341     /** An exception that contains autocompletion reply
342      */
343     class Completion : public Error
344     {
345         public:
346             Completion(const std::string &flag) : Error(flag) {}
347             virtual ~Completion() {}
348     };
349 #endif
350
351     /** A simple unified option type for unified initializer lists for the Matcher class.
352      */
353     struct EitherFlag
354     {
355         const bool isShort;
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() {}
361
362         /** Get just the long flags from an initializer list of EitherFlags
363          */
364         static std::unordered_set<std::string> GetLong(std::initializer_list<EitherFlag> flags)
365         {
366             std::unordered_set<std::string>  longFlags;
367             for (const EitherFlag &flag: flags)
368             {
369                 if (!flag.isShort)
370                 {
371                     longFlags.insert(flag.longFlag);
372                 }
373             }
374             return longFlags;
375         }
376
377         /** Get just the short flags from an initializer list of EitherFlags
378          */
379         static std::unordered_set<char> GetShort(std::initializer_list<EitherFlag> flags)
380         {
381             std::unordered_set<char>  shortFlags;
382             for (const EitherFlag &flag: flags)
383             {
384                 if (flag.isShort)
385                 {
386                     shortFlags.insert(flag.shortFlag);
387                 }
388             }
389             return shortFlags;
390         }
391
392         std::string str() const
393         {
394             return isShort ? std::string(1, shortFlag) : longFlag;
395         }
396
397         std::string str(const std::string &shortPrefix, const std::string &longPrefix) const
398         {
399             return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag;
400         }
401     };
402
403
404
405     /** A class of "matchers", specifying short and flags that can possibly be
406      * matched.
407      *
408      * This is supposed to be constructed and then passed in, not used directly
409      * from user code.
410      */
411     class Matcher
412     {
413         private:
414             const std::unordered_set<char> shortFlags;
415             const std::unordered_set<std::string> longFlags;
416
417         public:
418             /** Specify short and long flags separately as iterators
419              *
420              * ex: `args::Matcher(shortFlags.begin(), shortFlags.end(), longFlags.begin(), longFlags.end())`
421              */
422             template <typename ShortIt, typename LongIt>
423             Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd) :
424                 shortFlags(shortFlagsStart, shortFlagsEnd),
425                 longFlags(longFlagsStart, longFlagsEnd)
426             {
427                 if (shortFlags.empty() && longFlags.empty())
428                 {
429 #ifndef ARGS_NOEXCEPT
430                     throw UsageError("empty Matcher");
431 #endif
432                 }
433             }
434
435 #ifdef ARGS_NOEXCEPT
436             /// Only for ARGS_NOEXCEPT
437             Error GetError() const noexcept
438             {
439                 return shortFlags.empty() && longFlags.empty() ? Error::Usage : Error::None;
440             }
441 #endif
442
443             /** Specify short and long flags separately as iterables
444              *
445              * ex: `args::Matcher(shortFlags, longFlags)`
446              */
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))
450             {}
451
452             /** Specify a mixed single initializer-list of both short and long flags
453              *
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:
458              *
459              *     args::Matcher{'a'}
460              *     args::Matcher{"foo"}
461              *     args::Matcher{'h', "help"}
462              *     args::Matcher{"foo", 'f', 'F', "FoO"}
463              */
464             Matcher(std::initializer_list<EitherFlag> in) :
465                 Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {}
466
467             Matcher(Matcher &&other) noexcept : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags))
468             {}
469
470             ~Matcher() {}
471
472             /** (INTERNAL) Check if there is a match of a short flag
473              */
474             bool Match(const char flag) const
475             {
476                 return shortFlags.find(flag) != shortFlags.end();
477             }
478
479             /** (INTERNAL) Check if there is a match of a long flag
480              */
481             bool Match(const std::string &flag) const
482             {
483                 return longFlags.find(flag) != longFlags.end();
484             }
485
486             /** (INTERNAL) Check if there is a match of a flag
487              */
488             bool Match(const EitherFlag &flag) const
489             {
490                 return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag);
491             }
492
493             /** (INTERNAL) Get all flag strings as a vector, with the prefixes embedded
494              */
495             std::vector<EitherFlag> GetFlagStrings() const
496             {
497                 std::vector<EitherFlag> flagStrings;
498                 flagStrings.reserve(shortFlags.size() + longFlags.size());
499                 for (const char flag: shortFlags)
500                 {
501                     flagStrings.emplace_back(flag);
502                 }
503                 for (const std::string &flag: longFlags)
504                 {
505                     flagStrings.emplace_back(flag);
506                 }
507                 return flagStrings;
508             }
509
510             /** (INTERNAL) Get long flag if it exists or any short flag
511              */
512             EitherFlag GetLongOrAny() const
513             {
514                 if (!longFlags.empty())
515                 {
516                     return *longFlags.begin();
517                 }
518
519                 if (!shortFlags.empty())
520                 {
521                     return *shortFlags.begin();
522                 }
523
524                 // should be unreachable
525                 return ' ';
526             }
527
528             /** (INTERNAL) Get short flag if it exists or any long flag
529              */
530             EitherFlag GetShortOrAny() const
531             {
532                 if (!shortFlags.empty())
533                 {
534                     return *shortFlags.begin();
535                 }
536
537                 if (!longFlags.empty())
538                 {
539                     return *longFlags.begin();
540                 }
541
542                 // should be unreachable
543                 return ' ';
544             }
545     };
546
547     /** Attributes for flags.
548      */
549     enum class Options
550     {
551         /** Default options.
552          */
553         None = 0x0,
554
555         /** Flag can't be passed multiple times.
556          */
557         Single = 0x01,
558
559         /** Flag can't be omitted.
560          */
561         Required = 0x02,
562
563         /** Flag is excluded from usage line.
564          */
565         HiddenFromUsage = 0x04,
566
567         /** Flag is excluded from options help.
568          */
569         HiddenFromDescription = 0x08,
570
571         /** Flag is global and can be used in any subcommand.
572          */
573         Global = 0x10,
574
575         /** Flag stops a parser.
576          */
577         KickOut = 0x20,
578
579         /** Flag is excluded from auto completion.
580          */
581         HiddenFromCompletion = 0x40,
582
583         /** Flag is excluded from options help and usage line
584          */
585         Hidden = HiddenFromUsage | HiddenFromDescription | HiddenFromCompletion,
586     };
587
588     inline Options operator | (Options lhs, Options rhs)
589     {
590         return static_cast<Options>(static_cast<int>(lhs) | static_cast<int>(rhs));
591     }
592
593     inline Options operator & (Options lhs, Options rhs)
594     {
595         return static_cast<Options>(static_cast<int>(lhs) & static_cast<int>(rhs));
596     }
597
598     class FlagBase;
599     class PositionalBase;
600     class Command;
601     class ArgumentParser;
602
603     /** A simple structure of parameters for easy user-modifyable help menus
604      */
605     struct HelpParams
606     {
607         /** The width of the help menu
608          */
609         unsigned int width = 80;
610         /** The indent of the program line
611          */
612         unsigned int progindent = 2;
613         /** The indent of the program trailing lines for long parameters
614          */
615         unsigned int progtailindent = 4;
616         /** The indent of the description and epilogs
617          */
618         unsigned int descriptionindent = 4;
619         /** The indent of the flags
620          */
621         unsigned int flagindent = 6;
622         /** The indent of the flag descriptions
623          */
624         unsigned int helpindent = 40;
625         /** The additional indent each group adds
626          */
627         unsigned int eachgroupindent = 2;
628
629         /** The minimum gutter between each flag and its help
630          */
631         unsigned int gutter = 1;
632
633         /** Show the terminator when both options and positional parameters are present
634          */
635         bool showTerminator = true;
636
637         /** Show the {OPTIONS} on the prog line when this is true
638          */
639         bool showProglineOptions = true;
640
641         /** Show the positionals on the prog line when this is true
642          */
643         bool showProglinePositionals = true;
644
645         /** The prefix for short flags
646          */
647         std::string shortPrefix;
648
649         /** The prefix for long flags
650          */
651         std::string longPrefix;
652
653         /** The separator for short flags
654          */
655         std::string shortSeparator;
656
657         /** The separator for long flags
658          */
659         std::string longSeparator;
660
661         /** The program name for help generation
662          */
663         std::string programName;
664
665         /** Show command's flags
666          */
667         bool showCommandChildren = false;
668
669         /** Show command's descriptions and epilog
670          */
671         bool showCommandFullHelp = false;
672
673         /** The postfix for progline when showProglineOptions is true and command has any flags
674          */
675         std::string proglineOptions = "{OPTIONS}";
676
677         /** The prefix for progline when command has any subcommands
678          */
679         std::string proglineCommand = "COMMAND";
680
681         /** The prefix for progline value
682          */
683         std::string proglineValueOpen = " <";
684
685         /** The postfix for progline value
686          */
687         std::string proglineValueClose = ">";
688
689         /** The prefix for progline required argument
690          */
691         std::string proglineRequiredOpen = "";
692
693         /** The postfix for progline required argument
694          */
695         std::string proglineRequiredClose = "";
696
697         /** The prefix for progline non-required argument
698          */
699         std::string proglineNonrequiredOpen = "[";
700
701         /** The postfix for progline non-required argument
702          */
703         std::string proglineNonrequiredClose = "]";
704
705         /** Show flags in program line
706          */
707         bool proglineShowFlags = false;
708
709         /** Use short flags in program lines when possible
710          */
711         bool proglinePreferShortFlags = false;
712
713         /** Program line prefix
714          */
715         std::string usageString;
716
717         /** String shown in help before flags descriptions
718          */
719         std::string optionsString = "OPTIONS:";
720
721         /** Display value name after all the long and short flags
722          */
723         bool useValueNameOnce = false;
724
725         /** Show value name
726          */
727         bool showValueName = true;
728
729         /** Add newline before flag description
730          */
731         bool addNewlineBeforeDescription = false;
732
733         /** The prefix for option value
734          */
735         std::string valueOpen = "[";
736
737         /** The postfix for option value
738          */
739         std::string valueClose = "]";
740
741         /** Add choices to argument description
742          */
743         bool addChoices = false;
744
745         /** The prefix for choices
746          */
747         std::string choiceString = "\nOne of: ";
748
749         /** Add default values to argument description
750          */
751         bool addDefault = false;
752
753         /** The prefix for default values
754          */
755         std::string defaultString = "\nDefault: ";
756     };
757
758     /** A number of arguments which can be consumed by an option.
759      *
760      * Represents a closed interval [min, max].
761      */
762     struct Nargs
763     {
764         const size_t min;
765         const size_t max;
766
767         Nargs(size_t min_, size_t max_) : min{min_}, max{max_}
768         {
769 #ifndef ARGS_NOEXCEPT
770             if (max < min)
771             {
772                 throw UsageError("Nargs: max > min");
773             }
774 #endif
775         }
776
777         Nargs(size_t num_) : min{num_}, max{num_}
778         {
779         }
780
781         friend bool operator == (const Nargs &lhs, const Nargs &rhs)
782         {
783             return lhs.min == rhs.min && lhs.max == rhs.max;
784         }
785
786         friend bool operator != (const Nargs &lhs, const Nargs &rhs)
787         {
788             return !(lhs == rhs);
789         }
790     };
791
792     /** Base class for all match types
793      */
794     class Base
795     {
796         private:
797             Options options = {};
798
799         protected:
800             bool matched = false;
801             const std::string help;
802 #ifdef ARGS_NOEXCEPT
803             /// Only for ARGS_NOEXCEPT
804             mutable Error error = Error::None;
805             mutable std::string errorMsg;
806 #endif
807
808         public:
809             Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {}
810             virtual ~Base() {}
811
812             Options GetOptions() const noexcept
813             {
814                 return options;
815             }
816
817             bool IsRequired() const noexcept
818             {
819                 return (GetOptions() & Options::Required) != Options::None;
820             }
821
822             virtual bool Matched() const noexcept
823             {
824                 return matched;
825             }
826
827             virtual void Validate(const std::string &, const std::string &) const
828             {
829             }
830
831             operator bool() const noexcept
832             {
833                 return Matched();
834             }
835
836             virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &, const unsigned indentLevel) const
837             {
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) };
842             }
843
844             virtual std::vector<Command*> GetCommands()
845             {
846                 return {};
847             }
848
849             virtual bool IsGroup() const
850             {
851                 return false;
852             }
853
854             virtual FlagBase *Match(const EitherFlag &)
855             {
856                 return nullptr;
857             }
858
859             virtual PositionalBase *GetNextPositional()
860             {
861                 return nullptr;
862             }
863
864             virtual std::vector<FlagBase*> GetAllFlags()
865             {
866                 return {};
867             }
868
869             virtual bool HasFlag() const
870             {
871                 return false;
872             }
873
874             virtual bool HasPositional() const
875             {
876                 return false;
877             }
878
879             virtual bool HasCommand() const
880             {
881                 return false;
882             }
883
884             virtual std::vector<std::string> GetProgramLine(const HelpParams &) const
885             {
886                 return {};
887             }
888
889             /// Sets a kick-out value for building subparsers
890             void KickOut(bool kickout_) noexcept
891             {
892                 if (kickout_)
893                 {
894                     options = options | Options::KickOut;
895                 }
896                 else
897                 {
898                     options = static_cast<Options>(static_cast<int>(options) & ~static_cast<int>(Options::KickOut));
899                 }
900             }
901
902             /// Gets the kick-out value for building subparsers
903             bool KickOut() const noexcept
904             {
905                 return (options & Options::KickOut) != Options::None;
906             }
907
908             virtual void Reset() noexcept
909             {
910                 matched = false;
911 #ifdef ARGS_NOEXCEPT
912                 error = Error::None;
913                 errorMsg.clear();
914 #endif
915             }
916
917 #ifdef ARGS_NOEXCEPT
918             /// Only for ARGS_NOEXCEPT
919             virtual Error GetError() const
920             {
921                 return error;
922             }
923
924             /// Only for ARGS_NOEXCEPT
925             std::string GetErrorMsg() const
926             {
927                 return errorMsg;
928             }
929 #endif
930     };
931
932     /** Base class for all match types that have a name
933      */
934     class NamedBase : public Base
935     {
936         protected:
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;
943
944             virtual std::string GetDefaultString(const HelpParams&) const { return {}; }
945
946             virtual std::vector<std::string> GetChoicesStrings(const HelpParams&) const { return {}; }
947
948             virtual std::string GetNameString(const HelpParams&) const { return Name(); }
949
950             void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const
951             {
952                 if (isManual && !manual.empty())
953                 {
954                     dest += str;
955                     dest += manual;
956                 }
957                 else if (!isManual && isGenerated && !generated.empty())
958                 {
959                     dest += str;
960                     dest += generated;
961                 }
962             }
963
964         public:
965             NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {}
966             virtual ~NamedBase() {}
967
968             /** Sets default value string that will be added to argument description.
969              *  Use empty string to disable it for this argument.
970              */
971             void HelpDefault(const std::string &str)
972             {
973                 defaultStringManual = true;
974                 defaultString = str;
975             }
976
977             /** Gets default value string that will be added to argument description.
978              */
979             std::string HelpDefault(const HelpParams &params) const
980             {
981                 return defaultStringManual ? defaultString : GetDefaultString(params);
982             }
983
984             /** Sets choices strings that will be added to argument description.
985              *  Use empty vector to disable it for this argument.
986              */
987             void HelpChoices(const std::vector<std::string> &array)
988             {
989                 choicesStringManual = true;
990                 choicesStrings = array;
991             }
992
993             /** Gets choices strings that will be added to argument description.
994              */
995             std::vector<std::string> HelpChoices(const HelpParams &params) const
996             {
997                 return choicesStringManual ? choicesStrings : GetChoicesStrings(params);
998             }
999
1000             virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned indentLevel) const override
1001             {
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;
1006
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);
1009
1010                 return { std::move(description) };
1011             }
1012
1013             virtual std::string Name() const
1014             {
1015                 return name;
1016             }
1017     };
1018
1019     namespace detail
1020     {
1021         template<typename T>
1022         using vector = std::vector<T, std::allocator<T>>;
1023         
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> > >;
1027
1028         template<typename S, typename T>
1029         class is_streamable
1030         {
1031             template<typename SS, typename TT>
1032             static auto test(int)
1033             -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
1034
1035             template<typename, typename>
1036             static auto test(...) -> std::false_type;
1037
1038         public:
1039             using type = decltype(test<S,T>(0));
1040         };
1041
1042         template <typename T>
1043         using IsConvertableToString = typename is_streamable<std::ostringstream, T>::type;
1044
1045         template <typename T>
1046         typename std::enable_if<IsConvertableToString<T>::value, std::string>::type
1047         ToString(const T &value)
1048         {
1049             std::ostringstream s;
1050             s << value;
1051             return s.str();
1052         }
1053
1054         template <typename T>
1055         typename std::enable_if<!IsConvertableToString<T>::value, std::string>::type
1056         ToString(const T &)
1057         {
1058             return {};
1059         }
1060
1061         template <typename T>
1062         std::vector<std::string> MapKeysToStrings(const T &map)
1063         {
1064             std::vector<std::string> res;
1065             using K = typename std::decay<decltype(std::begin(map)->first)>::type;
1066             if (IsConvertableToString<K>::value)
1067             {
1068                 for (const auto &p : map)
1069                 {
1070                     res.push_back(detail::ToString(p.first));
1071                 }
1072
1073                 std::sort(res.begin(), res.end());
1074             }
1075             return res;
1076         }
1077     }
1078
1079     /** Base class for all flag options
1080      */
1081     class FlagBase : public NamedBase
1082     {
1083         protected:
1084             const Matcher matcher;
1085
1086             virtual std::string GetNameString(const HelpParams &params) const override
1087             {
1088                 const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name();
1089                 std::string flags;
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)
1093                 {
1094                     auto &flag = *it;
1095                     if (it != flagStrings.begin())
1096                     {
1097                         flags += ", ";
1098                     }
1099
1100                     flags += flag.isShort ? params.shortPrefix : params.longPrefix;
1101                     flags += flag.str();
1102
1103                     if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end()))
1104                     {
1105                         flags += flag.isShort ? params.shortSeparator : params.longSeparator;
1106                         flags += params.valueOpen + postfix + params.valueClose;
1107                     }
1108                 }
1109
1110                 return flags;
1111             }
1112
1113         public:
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_)) {}
1115
1116             FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {}
1117
1118             virtual ~FlagBase() {}
1119
1120             virtual FlagBase *Match(const EitherFlag &flag) override
1121             {
1122                 if (matcher.Match(flag))
1123                 {
1124                     if ((GetOptions() & Options::Single) != Options::None && matched)
1125                     {
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();
1131 #else
1132                         throw ExtraError(problem.str());
1133 #endif
1134                     }
1135                     matched = true;
1136                     return this;
1137                 }
1138                 return nullptr;
1139             }
1140
1141             virtual std::vector<FlagBase*> GetAllFlags() override
1142             {
1143                 return { this };
1144             }
1145
1146             const Matcher &GetMatcher() const
1147             {
1148                 return matcher;
1149             }
1150
1151             virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1152             {
1153                 if (!Matched() && IsRequired())
1154                 {
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();
1160 #else
1161                         throw RequiredError(problem.str());
1162 #endif
1163                 }
1164             }
1165
1166             virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1167             {
1168                 if (!params.proglineShowFlags)
1169                 {
1170                     return {};
1171                 }
1172
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())
1177                 {
1178                     res += params.proglineValueOpen + postfix + params.proglineValueClose;
1179                 }
1180
1181                 return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose
1182                                       : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose };
1183             }
1184
1185             virtual bool HasFlag() const override
1186             {
1187                 return true;
1188             }
1189
1190 #ifdef ARGS_NOEXCEPT
1191             /// Only for ARGS_NOEXCEPT
1192             virtual Error GetError() const override
1193             {
1194                 const auto nargs = NumberOfArguments();
1195                 if (nargs.min > nargs.max)
1196                 {
1197                     return Error::Usage;
1198                 }
1199
1200                 const auto matcherError = matcher.GetError();
1201                 if (matcherError != Error::None)
1202                 {
1203                     return matcherError;
1204                 }
1205
1206                 return error;
1207             }
1208 #endif
1209
1210             /** Defines how many values can be consumed by this option.
1211              *
1212              * \return closed interval [min, max]
1213              */
1214             virtual Nargs NumberOfArguments() const noexcept = 0;
1215
1216             /** Parse values of this option.
1217              *
1218              * \param value Vector of values. It's size must be in NumberOfArguments() interval.
1219              */
1220             virtual void ParseValue(const std::vector<std::string> &value) = 0;
1221     };
1222
1223     /** Base class for value-accepting flag options
1224      */
1225     class ValueFlagBase : public FlagBase
1226     {
1227         public:
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() {}
1231
1232             virtual Nargs NumberOfArguments() const noexcept override
1233             {
1234                 return 1;
1235             }
1236     };
1237
1238     class CompletionFlag : public ValueFlagBase
1239     {
1240         public:
1241             std::vector<std::string> reply;
1242             size_t cword = 0;
1243             std::string syntax;
1244
1245             template <typename GroupClass>
1246             CompletionFlag(GroupClass &group_, Matcher &&matcher_): ValueFlagBase("completion", "completion flag", std::move(matcher_), Options::Hidden)
1247             {
1248                 group_.AddCompletion(*this);
1249             }
1250
1251             virtual ~CompletionFlag() {}
1252
1253             virtual Nargs NumberOfArguments() const noexcept override
1254             {
1255                 return 2;
1256             }
1257
1258             virtual void ParseValue(const std::vector<std::string> &value_) override
1259             {
1260                 syntax = value_.at(0);
1261                 std::istringstream(value_.at(1)) >> cword;
1262             }
1263
1264             /** Get the completion reply
1265              */
1266             std::string Get() noexcept
1267             {
1268                 return detail::Join(reply, "\n");
1269             }
1270
1271             virtual void Reset() noexcept override
1272             {
1273                 ValueFlagBase::Reset();
1274                 cword = 0;
1275                 syntax.clear();
1276                 reply.clear();
1277             }
1278     };
1279
1280
1281     /** Base class for positional options
1282      */
1283     class PositionalBase : public NamedBase
1284     {
1285         protected:
1286             bool ready;
1287
1288         public:
1289             PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {}
1290             virtual ~PositionalBase() {}
1291
1292             bool Ready()
1293             {
1294                 return ready;
1295             }
1296
1297             virtual void ParseValue(const std::string &value_) = 0;
1298
1299             virtual void Reset() noexcept override
1300             {
1301                 matched = false;
1302                 ready = true;
1303 #ifdef ARGS_NOEXCEPT
1304                 error = Error::None;
1305                 errorMsg.clear();
1306 #endif
1307             }
1308
1309             virtual PositionalBase *GetNextPositional() override
1310             {
1311                 return Ready() ? this : nullptr;
1312             }
1313
1314             virtual bool HasPositional() const override
1315             {
1316                 return true;
1317             }
1318
1319             virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1320             {
1321                 return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose
1322                                       : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose };
1323             }
1324
1325             virtual void Validate(const std::string &, const std::string &) const override
1326             {
1327                 if (IsRequired() && !Matched())
1328                 {
1329                     std::ostringstream problem;
1330                     problem << "Option '" << Name() << "' is required";
1331 #ifdef ARGS_NOEXCEPT
1332                     error = Error::Required;
1333                     errorMsg = problem.str();
1334 #else
1335                     throw RequiredError(problem.str());
1336 #endif
1337                 }
1338             }
1339     };
1340
1341     /** Class for all kinds of validating groups, including ArgumentParser
1342      */
1343     class Group : public Base
1344     {
1345         private:
1346             std::vector<Base*> children;
1347             std::function<bool(const Group &)> validator;
1348
1349         public:
1350             /** Default validators
1351              */
1352             struct Validators
1353             {
1354                 static bool Xor(const Group &group)
1355                 {
1356                     return group.MatchedChildren() == 1;
1357                 }
1358
1359                 static bool AtLeastOne(const Group &group)
1360                 {
1361                     return group.MatchedChildren() >= 1;
1362                 }
1363
1364                 static bool AtMostOne(const Group &group)
1365                 {
1366                     return group.MatchedChildren() <= 1;
1367                 }
1368
1369                 static bool All(const Group &group)
1370                 {
1371                     return group.Children().size() == group.MatchedChildren();
1372                 }
1373
1374                 static bool AllOrNone(const Group &group)
1375                 {
1376                     return (All(group) || None(group));
1377                 }
1378
1379                 static bool AllChildGroups(const Group &group)
1380                 {
1381                     return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool {
1382                             return child->IsGroup() && !child->Matched();
1383                             });
1384                 }
1385
1386                 static bool DontCare(const Group &)
1387                 {
1388                     return true;
1389                 }
1390
1391                 static bool CareTooMuch(const Group &)
1392                 {
1393                     return false;
1394                 }
1395
1396                 static bool None(const Group &group)
1397                 {
1398                     return group.MatchedChildren() == 0;
1399                 }
1400             };
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_)
1405             {
1406                 group_.Add(*this);
1407             }
1408             virtual ~Group() {}
1409
1410             /** Append a child to this Group.
1411              */
1412             void Add(Base &child)
1413             {
1414                 children.emplace_back(&child);
1415             }
1416
1417             /** Get all this group's children
1418              */
1419             const std::vector<Base *> &Children() const
1420             {
1421                 return children;
1422             }
1423
1424             /** Return the first FlagBase that matches flag, or nullptr
1425              *
1426              * \param flag The flag with prefixes stripped
1427              * \return the first matching FlagBase pointer, or nullptr if there is no match
1428              */
1429             virtual FlagBase *Match(const EitherFlag &flag) override
1430             {
1431                 for (Base *child: Children())
1432                 {
1433                     if (FlagBase *match = child->Match(flag))
1434                     {
1435                         return match;
1436                     }
1437                 }
1438                 return nullptr;
1439             }
1440
1441             virtual std::vector<FlagBase*> GetAllFlags() override
1442             {
1443                 std::vector<FlagBase*> res;
1444                 for (Base *child: Children())
1445                 {
1446                     auto childRes = child->GetAllFlags();
1447                     res.insert(res.end(), childRes.begin(), childRes.end());
1448                 }
1449                 return res;
1450             }
1451
1452             virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1453             {
1454                 for (Base *child: Children())
1455                 {
1456                     child->Validate(shortPrefix, longPrefix);
1457                 }
1458             }
1459
1460             /** Get the next ready positional, or nullptr if there is none
1461              *
1462              * \return the first ready PositionalBase pointer, or nullptr if there is no match
1463              */
1464             virtual PositionalBase *GetNextPositional() override
1465             {
1466                 for (Base *child: Children())
1467                 {
1468                     if (auto next = child->GetNextPositional())
1469                     {
1470                         return next;
1471                     }
1472                 }
1473                 return nullptr;
1474             }
1475
1476             /** Get whether this has any FlagBase children
1477              *
1478              * \return Whether or not there are any FlagBase children
1479              */
1480             virtual bool HasFlag() const override
1481             {
1482                 return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); });
1483             }
1484
1485             /** Get whether this has any PositionalBase children
1486              *
1487              * \return Whether or not there are any PositionalBase children
1488              */
1489             virtual bool HasPositional() const override
1490             {
1491                 return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); });
1492             }
1493
1494             /** Get whether this has any Command children
1495              *
1496              * \return Whether or not there are any Command children
1497              */
1498             virtual bool HasCommand() const override
1499             {
1500                 return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); });
1501             }
1502
1503             /** Count the number of matched children this group has
1504              */
1505             std::vector<Base *>::size_type MatchedChildren() const
1506             {
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();}));
1510             }
1511
1512             /** Whether or not this group matches validation
1513              */
1514             virtual bool Matched() const noexcept override
1515             {
1516                 return validator(*this);
1517             }
1518
1519             /** Get validation
1520              */
1521             bool Get() const
1522             {
1523                 return Matched();
1524             }
1525
1526             /** Get all the child descriptions for help generation
1527              */
1528             virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
1529             {
1530                 std::vector<std::tuple<std::string, std::string, unsigned int>> descriptions;
1531
1532                 // Push that group description on the back if not empty
1533                 unsigned addindent = 0;
1534                 if (!help.empty())
1535                 {
1536                     descriptions.emplace_back(help, "", indent);
1537                     addindent = 1;
1538                 }
1539
1540                 for (Base *child: Children())
1541                 {
1542                     if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
1543                     {
1544                         continue;
1545                     }
1546
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)));
1552                 }
1553                 return descriptions;
1554             }
1555
1556             /** Get the names of positional parameters
1557              */
1558             virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1559             {
1560                 std::vector <std::string> names;
1561                 for (Base *child: Children())
1562                 {
1563                     if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None)
1564                     {
1565                         continue;
1566                     }
1567
1568                     auto groupNames = child->GetProgramLine(params);
1569                     names.insert(
1570                         std::end(names),
1571                         std::make_move_iterator(std::begin(groupNames)),
1572                         std::make_move_iterator(std::end(groupNames)));
1573                 }
1574                 return names;
1575             }
1576
1577             virtual std::vector<Command*> GetCommands() override
1578             {
1579                 std::vector<Command*> res;
1580                 for (const auto &child : Children())
1581                 {
1582                     auto subparsers = child->GetCommands();
1583                     res.insert(std::end(res), std::begin(subparsers), std::end(subparsers));
1584                 }
1585                 return res;
1586             }
1587
1588             virtual bool IsGroup() const override
1589             {
1590                 return true;
1591             }
1592
1593             virtual void Reset() noexcept override
1594             {
1595                 Base::Reset();
1596
1597                 for (auto &child: Children())
1598                 {
1599                     child->Reset();
1600                 }
1601 #ifdef ARGS_NOEXCEPT
1602                 error = Error::None;
1603                 errorMsg.clear();
1604 #endif
1605             }
1606
1607 #ifdef ARGS_NOEXCEPT
1608             /// Only for ARGS_NOEXCEPT
1609             virtual Error GetError() const override
1610             {
1611                 if (error != Error::None)
1612                 {
1613                     return error;
1614                 }
1615
1616                 auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;});
1617                 if (it == Children().end())
1618                 {
1619                     return Error::None;
1620                 } else
1621                 {
1622                     return (*it)->GetError();
1623                 }
1624             }
1625 #endif
1626
1627     };
1628
1629     /** Class for using global options in ArgumentParser.
1630      */
1631     class GlobalOptions : public Group
1632     {
1633         public:
1634             GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global)
1635             {
1636                 Add(options_);
1637             }
1638     };
1639
1640     /** Utility class for building subparsers with coroutines/callbacks.
1641      *
1642      * Brief example:
1643      * \code
1644      * Command command(argumentParser, "command", "my command", [](args::Subparser &s)
1645      * {
1646      *      // your command flags/positionals
1647      *      s.Parse(); //required
1648      *      //your command code
1649      * });
1650      * \endcode
1651      *
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.
1654      *
1655      * \sa Command
1656      */
1657     class Subparser : public Group
1658     {
1659         private:
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;
1666
1667         public:
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_)
1670             {
1671             }
1672
1673             Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_)
1674             {
1675             }
1676
1677             Subparser(const Subparser&) = delete;
1678             Subparser(Subparser&&) = delete;
1679             Subparser &operator = (const Subparser&) = delete;
1680             Subparser &operator = (Subparser&&) = delete;
1681
1682             const Command &GetCommand()
1683             {
1684                 return command;
1685             }
1686
1687             /** (INTERNAL) Determines whether Parse was called or not.
1688              */
1689             bool IsParsed() const
1690             {
1691                 return isParsed;
1692             }
1693
1694             /** Continue parsing arguments for new command.
1695              */
1696             void Parse();
1697
1698             /** Returns a vector of kicked out arguments.
1699              *
1700              * \sa Base::KickOut
1701              */
1702             const std::vector<std::string> &KickedOut() const noexcept
1703             {
1704                 return kicked;
1705             }
1706     };
1707
1708     /** Main class for building subparsers.
1709      *
1710      * /sa Subparser
1711      */
1712     class Command : public Group
1713     {
1714         private:
1715             friend class Subparser;
1716
1717             std::string name;
1718             std::string help;
1719             std::string description;
1720             std::string epilog;
1721             std::string proglinePostfix;
1722
1723             std::function<void(Subparser&)> parserCoroutine;
1724             bool commandIsRequired = true;
1725             Command *selectedCommand = nullptr;
1726
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;
1734 #endif
1735             mutable Subparser *subparser = nullptr;
1736
1737         protected:
1738
1739             class RaiiSubparser
1740             {
1741                 public:
1742                     RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_);
1743                     RaiiSubparser(const Command &command_, const HelpParams &params_);
1744
1745                     ~RaiiSubparser()
1746                     {
1747                         command.subparser = oldSubparser;
1748                     }
1749
1750                     Subparser &Parser()
1751                     {
1752                         return parser;
1753                     }
1754
1755                 private:
1756                     const Command &command;
1757                     Subparser parser;
1758                     Subparser *oldSubparser;
1759             };
1760
1761             Command() = default;
1762
1763             std::function<void(Subparser&)> &GetCoroutine()
1764             {
1765                 return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine;
1766             }
1767
1768             Command &SelectedCommand()
1769             {
1770                 Command *res = this;
1771                 while (res->selectedCommand != nullptr)
1772                 {
1773                     res = res->selectedCommand;
1774                 }
1775
1776                 return *res;
1777             }
1778
1779             const Command &SelectedCommand() const
1780             {
1781                 const Command *res = this;
1782                 while (res->selectedCommand != nullptr)
1783                 {
1784                     res = res->selectedCommand;
1785                 }
1786
1787                 return *res;
1788             }
1789
1790             void UpdateSubparserHelp(const HelpParams &params) const
1791             {
1792                 if (parserCoroutine)
1793                 {
1794                     RaiiSubparser coro(*this, params);
1795 #ifndef ARGS_NOEXCEPT
1796                     try
1797                     {
1798                         parserCoroutine(coro.Parser());
1799                     }
1800                     catch (args::SubparserError&)
1801                     {
1802                     }
1803 #else
1804                     parserCoroutine(coro.Parser());
1805 #endif
1806                 }
1807             }
1808
1809         public:
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_))
1812             {
1813                 base_.Add(*this);
1814             }
1815
1816             /** The description that appears on the prog line after options
1817              */
1818             const std::string &ProglinePostfix() const
1819             { return proglinePostfix; }
1820
1821             /** The description that appears on the prog line after options
1822              */
1823             void ProglinePostfix(const std::string &proglinePostfix_)
1824             { this->proglinePostfix = proglinePostfix_; }
1825
1826             /** The description that appears above options
1827              */
1828             const std::string &Description() const
1829             { return description; }
1830             /** The description that appears above options
1831              */
1832
1833             void Description(const std::string &description_)
1834             { this->description = description_; }
1835
1836             /** The description that appears below options
1837              */
1838             const std::string &Epilog() const
1839             { return epilog; }
1840
1841             /** The description that appears below options
1842              */
1843             void Epilog(const std::string &epilog_)
1844             { this->epilog = epilog_; }
1845
1846             /** The name of command
1847              */
1848             const std::string &Name() const
1849             { return name; }
1850
1851             /** The description of command
1852              */
1853             const std::string &Help() const
1854             { return help; }
1855
1856             /** If value is true, parser will fail if no command was parsed.
1857              *
1858              * Default: true.
1859              */
1860             void RequireCommand(bool value)
1861             { commandIsRequired = value; }
1862
1863             virtual bool IsGroup() const override
1864             { return false; }
1865
1866             virtual bool Matched() const noexcept override
1867             { return Base::Matched(); }
1868
1869             operator bool() const noexcept
1870             { return Matched(); }
1871
1872             void Match() noexcept
1873             { matched = true; }
1874
1875             void SelectCommand(Command *c) noexcept
1876             {
1877                 selectedCommand = c;
1878
1879                 if (c != nullptr)
1880                 {
1881                     c->Match();
1882                 }
1883             }
1884
1885             virtual FlagBase *Match(const EitherFlag &flag) override
1886             {
1887                 if (selectedCommand != nullptr)
1888                 {
1889                     if (auto *res = selectedCommand->Match(flag))
1890                     {
1891                         return res;
1892                     }
1893
1894                     for (auto *child: Children())
1895                     {
1896                         if ((child->GetOptions() & Options::Global) != Options::None)
1897                         {
1898                             if (auto *res = child->Match(flag))
1899                             {
1900                                 return res;
1901                             }
1902                         }
1903                     }
1904
1905                     return nullptr;
1906                 }
1907
1908                 if (subparser != nullptr)
1909                 {
1910                     return subparser->Match(flag);
1911                 }
1912
1913                 return Matched() ? Group::Match(flag) : nullptr;
1914             }
1915
1916             virtual std::vector<FlagBase*> GetAllFlags() override
1917             {
1918                 std::vector<FlagBase*> res;
1919
1920                 if (!Matched())
1921                 {
1922                     return res;
1923                 }
1924
1925                 for (auto *child: Children())
1926                 {
1927                     if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None)
1928                     {
1929                         auto childFlags = child->GetAllFlags();
1930                         res.insert(res.end(), childFlags.begin(), childFlags.end());
1931                     }
1932                 }
1933
1934                 if (selectedCommand != nullptr)
1935                 {
1936                     auto childFlags = selectedCommand->GetAllFlags();
1937                     res.insert(res.end(), childFlags.begin(), childFlags.end());
1938                 }
1939
1940                 if (subparser != nullptr)
1941                 {
1942                     auto childFlags = subparser->GetAllFlags();
1943                     res.insert(res.end(), childFlags.begin(), childFlags.end());
1944                 }
1945
1946                 return res;
1947             }
1948
1949             virtual PositionalBase *GetNextPositional() override
1950             {
1951                 if (selectedCommand != nullptr)
1952                 {
1953                     if (auto *res = selectedCommand->GetNextPositional())
1954                     {
1955                         return res;
1956                     }
1957
1958                     for (auto *child: Children())
1959                     {
1960                         if ((child->GetOptions() & Options::Global) != Options::None)
1961                         {
1962                             if (auto *res = child->GetNextPositional())
1963                             {
1964                                 return res;
1965                             }
1966                         }
1967                     }
1968
1969                     return nullptr;
1970                 }
1971
1972                 if (subparser != nullptr)
1973                 {
1974                     return subparser->GetNextPositional();
1975                 }
1976
1977                 return Matched() ? Group::GetNextPositional() : nullptr;
1978             }
1979
1980             virtual bool HasFlag() const override
1981             {
1982                 return subparserHasFlag || Group::HasFlag();
1983             }
1984
1985             virtual bool HasPositional() const override
1986             {
1987                 return subparserHasPositional || Group::HasPositional();
1988             }
1989
1990             virtual bool HasCommand() const override
1991             {
1992                 return true;
1993             }
1994
1995             std::vector<std::string> GetCommandProgramLine(const HelpParams &params) const
1996             {
1997                 UpdateSubparserHelp(params);
1998
1999                 auto res = Group::GetProgramLine(params);
2000                 res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end());
2001
2002                 if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand))
2003                 {
2004                     res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]");
2005                 }
2006
2007                 if (!Name().empty())
2008                 {
2009                     res.insert(res.begin(), Name());
2010                 }
2011
2012                 if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags)
2013                 {
2014                     res.push_back(params.proglineOptions);
2015                 }
2016
2017                 if (!ProglinePostfix().empty())
2018                 {
2019                     std::string line;
2020                     for (auto c : ProglinePostfix())
2021                     {
2022                         if (std::isspace(static_cast<unsigned char>(c)))
2023                         {
2024                             if (!line.empty())
2025                             {
2026                                 res.push_back(line);
2027                                 line.clear();
2028                             }
2029
2030                             if (c == '\n')
2031                             {
2032                                 res.push_back("\n");
2033                             }
2034                         }
2035                         else
2036                         {
2037                             line += c;
2038                         }
2039                     }
2040
2041                     if (!line.empty())
2042                     {
2043                         res.push_back(line);
2044                     }
2045                 }
2046
2047                 return res;
2048             }
2049
2050             virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
2051             {
2052                 if (!Matched())
2053                 {
2054                     return {};
2055                 }
2056
2057                 return GetCommandProgramLine(params);
2058             }
2059
2060             virtual std::vector<Command*> GetCommands() override
2061             {
2062                 if (selectedCommand != nullptr)
2063                 {
2064                     return selectedCommand->GetCommands();
2065                 }
2066
2067                 if (Matched())
2068                 {
2069                     return Group::GetCommands();
2070                 }
2071
2072                 return { this };
2073             }
2074
2075             virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
2076             {
2077                 std::vector<std::tuple<std::string, std::string, unsigned>> descriptions;
2078                 unsigned addindent = 0;
2079
2080                 UpdateSubparserHelp(params);
2081
2082                 if (!Matched())
2083                 {
2084                     if (params.showCommandFullHelp)
2085                     {
2086                         std::ostringstream s;
2087                         bool empty = true;
2088                         for (const auto &progline: GetCommandProgramLine(params))
2089                         {
2090                             if (!empty)
2091                             {
2092                                 s << ' ';
2093                             }
2094                             else
2095                             {
2096                                 empty = false;
2097                             }
2098
2099                             s << progline;
2100                         }
2101
2102                         descriptions.emplace_back(s.str(), "", indent);
2103                     }
2104                     else
2105                     {
2106                         descriptions.emplace_back(Name(), help, indent);
2107                     }
2108
2109                     if (!params.showCommandChildren && !params.showCommandFullHelp)
2110                     {
2111                         return descriptions;
2112                     }
2113
2114                     addindent = 1;
2115                 }
2116
2117                 if (params.showCommandFullHelp && !Matched())
2118                 {
2119                     descriptions.emplace_back("", "", indent + addindent);
2120                     descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent);
2121                     descriptions.emplace_back("", "", indent + addindent);
2122                 }
2123
2124                 for (Base *child: Children())
2125                 {
2126                     if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
2127                     {
2128                         continue;
2129                     }
2130
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)));
2136                 }
2137
2138                 for (auto childDescription: subparserDescription)
2139                 {
2140                     std::get<2>(childDescription) += indent + addindent;
2141                     descriptions.push_back(std::move(childDescription));
2142                 }
2143
2144                 if (params.showCommandFullHelp && !Matched())
2145                 {
2146                     descriptions.emplace_back("", "", indent + addindent);
2147                     if (!Epilog().empty())
2148                     {
2149                         descriptions.emplace_back(Epilog(), "", indent + addindent);
2150                         descriptions.emplace_back("", "", indent + addindent);
2151                     }
2152                 }
2153
2154                 return descriptions;
2155             }
2156
2157             virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override
2158             {
2159                 if (!Matched())
2160                 {
2161                     return;
2162                 }
2163
2164                 auto onValidationError = [&]
2165                 {
2166                     std::ostringstream problem;
2167                     problem << "Group validation failed somewhere!";
2168 #ifdef ARGS_NOEXCEPT
2169                     error = Error::Validation;
2170                     errorMsg = problem.str();
2171 #else
2172                     throw ValidationError(problem.str());
2173 #endif
2174                 };
2175
2176                 for (Base *child: Children())
2177                 {
2178                     if (child->IsGroup() && !child->Matched())
2179                     {
2180                         onValidationError();
2181                     }
2182
2183                     child->Validate(shortprefix, longprefix);
2184                 }
2185
2186                 if (subparser != nullptr)
2187                 {
2188                     subparser->Validate(shortprefix, longprefix);
2189                     if (!subparser->Matched())
2190                     {
2191                         onValidationError();
2192                     }
2193                 }
2194
2195                 if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand))
2196                 {
2197                     std::ostringstream problem;
2198                     problem << "Command is required";
2199 #ifdef ARGS_NOEXCEPT
2200                     error = Error::Validation;
2201                     errorMsg = problem.str();
2202 #else
2203                     throw ValidationError(problem.str());
2204 #endif
2205                 }
2206             }
2207
2208             virtual void Reset() noexcept override
2209             {
2210                 Group::Reset();
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;
2219 #endif
2220             }
2221
2222 #ifdef ARGS_NOEXCEPT
2223             /// Only for ARGS_NOEXCEPT
2224             virtual Error GetError() const override
2225             {
2226                 if (!Matched())
2227                 {
2228                     return Error::None;
2229                 }
2230
2231                 if (error != Error::None)
2232                 {
2233                     return error;
2234                 }
2235
2236                 if (subparserError != Error::None)
2237                 {
2238                     return subparserError;
2239                 }
2240
2241                 return Group::GetError();
2242             }
2243 #endif
2244     };
2245
2246     /** The main user facing command line argument parser class
2247      */
2248     class ArgumentParser : public Command
2249     {
2250         friend class Subparser;
2251
2252         private:
2253             std::string longprefix;
2254             std::string shortprefix;
2255
2256             std::string longseparator;
2257
2258             std::string terminator;
2259
2260             bool allowJoinedShortValue = true;
2261             bool allowJoinedLongValue = true;
2262             bool allowSeparateShortValue = true;
2263             bool allowSeparateLongValue = true;
2264
2265             CompletionFlag *completion = nullptr;
2266             bool readCompletion = false;
2267
2268         protected:
2269             enum class OptionType
2270             {
2271                 LongFlag,
2272                 ShortFlag,
2273                 Positional
2274             };
2275
2276             OptionType ParseOption(const std::string &s, bool allowEmpty = false)
2277             {
2278                 if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length()))
2279                 {
2280                     return OptionType::LongFlag;
2281                 }
2282
2283                 if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length()))
2284                 {
2285                     return OptionType::ShortFlag;
2286                 }
2287
2288                 return OptionType::Positional;
2289             }
2290
2291             template <typename It>
2292             bool Complete(FlagBase &flag, It it, It end)
2293             {
2294                 auto nextIt = it;
2295                 if (!readCompletion || (++nextIt != end))
2296                 {
2297                     return false;
2298                 }
2299
2300                 const auto &chunk = *it;
2301                 for (auto &choice : flag.HelpChoices(helpParams))
2302                 {
2303                     AddCompletionReply(chunk, choice);
2304                 }
2305
2306 #ifndef ARGS_NOEXCEPT
2307                 throw Completion(completion->Get());
2308 #else
2309                 return true;
2310 #endif
2311             }
2312
2313             /** (INTERNAL) Parse flag's values
2314              *
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
2321              */
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)
2327             {
2328                 values.clear();
2329
2330                 Nargs nargs = flag.NumberOfArguments();
2331
2332                 if (hasJoined && !allowJoined && nargs.min != 0)
2333                 {
2334                     return "Flag '" + arg + "' was passed a joined argument, but these are disallowed";
2335                 }
2336
2337                 if (hasJoined)
2338                 {
2339                     if (!canDiscardJoined || nargs.max != 0)
2340                     {
2341                         values.push_back(joinedArg);
2342                     }
2343                 } else if (!allowSeparate)
2344                 {
2345                     if (nargs.min != 0)
2346                     {
2347                         return "Flag '" + arg + "' was passed a separate argument, but these are disallowed";
2348                     }
2349                 } else
2350                 {
2351                     auto valueIt = it;
2352                     ++valueIt;
2353
2354                     while (valueIt != end &&
2355                            values.size() < nargs.max &&
2356                            (values.size() < nargs.min || ParseOption(*valueIt) == OptionType::Positional))
2357                     {
2358                         if (Complete(flag, valueIt, end))
2359                         {
2360                             it = end;
2361                             return "";
2362                         }
2363
2364                         values.push_back(*valueIt);
2365                         ++it;
2366                         ++valueIt;
2367                     }
2368                 }
2369
2370                 if (values.size() > nargs.max)
2371                 {
2372                     return "Passed an argument into a non-argument flag: " + arg;
2373                 } else if (values.size() < nargs.min)
2374                 {
2375                     if (nargs.min == 1 && nargs.max == 1)
2376                     {
2377                         return "Flag '" + arg + "' requires an argument but received none";
2378                     } else if (nargs.min == 1)
2379                     {
2380                         return "Flag '" + arg + "' requires at least one argument but received none";
2381                     } else if (nargs.min != nargs.max)
2382                     {
2383                         return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) +
2384                                " arguments but received " + std::to_string(values.size());
2385                     } else
2386                     {
2387                         return "Flag '" + arg + "' requires " + std::to_string(nargs.min) +
2388                                " arguments but received " + std::to_string(values.size());
2389                     }
2390                 }
2391
2392                 return {};
2393             }
2394
2395             template <typename It>
2396             bool ParseLong(It &it, It end)
2397             {
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)
2405                     : argchunk);
2406                 const auto joined = (separator != argchunk.npos ?
2407                     argchunk.substr(separator + longseparator.size())
2408                     : std::string());
2409
2410                 if (auto flag = Match(arg))
2411                 {
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())
2416                     {
2417 #ifndef ARGS_NOEXCEPT
2418                         throw ParseError(errorMessage);
2419 #else
2420                         error = Error::Parse;
2421                         errorMsg = errorMessage;
2422                         return false;
2423 #endif
2424                     }
2425
2426                     if (!readCompletion)
2427                     {
2428                         flag->ParseValue(values);
2429                     }
2430
2431                     if (flag->KickOut())
2432                     {
2433                         ++it;
2434                         return false;
2435                     }
2436                 } else
2437                 {
2438                     const std::string errorMessage("Flag could not be matched: " + arg);
2439 #ifndef ARGS_NOEXCEPT
2440                     throw ParseError(errorMessage);
2441 #else
2442                     error = Error::Parse;
2443                     errorMsg = errorMessage;
2444                     return false;
2445 #endif
2446                 }
2447
2448                 return true;
2449             }
2450
2451             template <typename It>
2452             bool ParseShort(It &it, It end)
2453             {
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)
2457                 {
2458                     const auto arg = *argit;
2459
2460                     if (auto flag = Match(arg))
2461                     {
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);
2467
2468                         if (!errorMessage.empty())
2469                         {
2470 #ifndef ARGS_NOEXCEPT
2471                             throw ParseError(errorMessage);
2472 #else
2473                             error = Error::Parse;
2474                             errorMsg = errorMessage;
2475                             return false;
2476 #endif
2477                         }
2478
2479                         if (!readCompletion)
2480                         {
2481                             flag->ParseValue(values);
2482                         }
2483
2484                         if (flag->KickOut())
2485                         {
2486                             ++it;
2487                             return false;
2488                         }
2489
2490                         if (!values.empty())
2491                         {
2492                             break;
2493                         }
2494                     } else
2495                     {
2496                         const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'");
2497 #ifndef ARGS_NOEXCEPT
2498                         throw ParseError(errorMessage);
2499 #else
2500                         error = Error::Parse;
2501                         errorMsg = errorMessage;
2502                         return false;
2503 #endif
2504                     }
2505                 }
2506
2507                 return true;
2508             }
2509
2510             bool AddCompletionReply(const std::string &cur, const std::string &choice)
2511             {
2512                 if (cur.empty() || choice.find(cur) == 0)
2513                 {
2514                     if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos)
2515                     {
2516                         completion->reply.push_back(choice.substr(choice.find(longseparator) + 1));
2517                     } else
2518                     {
2519                         completion->reply.push_back(choice);
2520                     }
2521                     return true;
2522                 }
2523
2524                 return false;
2525             }
2526
2527             template <typename It>
2528             bool Complete(It it, It end)
2529             {
2530                 auto nextIt = it;
2531                 if (!readCompletion || (++nextIt != end))
2532                 {
2533                     return false;
2534                 }
2535
2536                 const auto &chunk = *it;
2537                 auto pos = GetNextPositional();
2538                 std::vector<Command *> commands = GetCommands();
2539                 const auto optionType = ParseOption(chunk, true);
2540
2541                 if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
2542                 {
2543                     for (auto &cmd : commands)
2544                     {
2545                         if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2546                         {
2547                             AddCompletionReply(chunk, cmd->Name());
2548                         }
2549                     }
2550                 } else
2551                 {
2552                     bool hasPositionalCompletion = true;
2553
2554                     if (!commands.empty())
2555                     {
2556                         for (auto &cmd : commands)
2557                         {
2558                             if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2559                             {
2560                                 AddCompletionReply(chunk, cmd->Name());
2561                             }
2562                         }
2563                     } else if (pos)
2564                     {
2565                         if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2566                         {
2567                             auto choices = pos->HelpChoices(helpParams);
2568                             hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
2569                             for (auto &choice : choices)
2570                             {
2571                                 AddCompletionReply(chunk, choice);
2572                             }
2573                         }
2574                     }
2575
2576                     if (hasPositionalCompletion)
2577                     {
2578                         auto flags = GetAllFlags();
2579                         for (auto flag : flags)
2580                         {
2581                             if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None)
2582                             {
2583                                 continue;
2584                             }
2585
2586                             auto &matcher = flag->GetMatcher();
2587                             if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix)))
2588                             {
2589                                 for (auto &flagName : matcher.GetFlagStrings())
2590                                 {
2591                                     if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix)))
2592                                     {
2593                                         break;
2594                                     }
2595                                 }
2596                             }
2597                         }
2598
2599                         if (optionType == OptionType::LongFlag && allowJoinedLongValue)
2600                         {
2601                             const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
2602                             if (separator != chunk.npos)
2603                             {
2604                                 std::string arg(chunk, 0, separator);
2605                                 if (auto flag = this->Match(arg.substr(longprefix.size())))
2606                                 {
2607                                     for (auto &choice : flag->HelpChoices(helpParams))
2608                                     {
2609                                         AddCompletionReply(chunk, arg + longseparator + choice);
2610                                     }
2611                                 }
2612                             }
2613                         } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
2614                         {
2615                             if (chunk.size() > shortprefix.size() + 1)
2616                             {
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))
2620                                 {
2621                                     for (auto &choice : flag->HelpChoices(helpParams))
2622                                     {
2623                                         AddCompletionReply(chunk, shortprefix + arg + choice);
2624                                     }
2625                                 }
2626                             }
2627                         }
2628                     }
2629                 }
2630
2631 #ifndef ARGS_NOEXCEPT
2632                 throw Completion(completion->Get());
2633 #else
2634                 return true;
2635 #endif
2636             }
2637
2638             template <typename It>
2639             It Parse(It begin, It end)
2640             {
2641                 bool terminated = false;
2642                 std::vector<Command *> commands = GetCommands();
2643
2644                 // Check all arg chunks
2645                 for (auto it = begin; it != end; ++it)
2646                 {
2647                     if (Complete(it, end))
2648                     {
2649                         return end;
2650                     }
2651
2652                     const auto &chunk = *it;
2653
2654                     if (!terminated && chunk == terminator)
2655                     {
2656                         terminated = true;
2657                     } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag)
2658                     {
2659                         if (!ParseLong(it, end))
2660                         {
2661                             return it;
2662                         }
2663                     } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag)
2664                     {
2665                         if (!ParseShort(it, end))
2666                         {
2667                             return it;
2668                         }
2669                     } else if (!terminated && !commands.empty())
2670                     {
2671                         auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; });
2672                         if (itCommand == commands.end())
2673                         {
2674                             const std::string errorMessage("Unknown command: " + chunk);
2675 #ifndef ARGS_NOEXCEPT
2676                             throw ParseError(errorMessage);
2677 #else
2678                             error = Error::Parse;
2679                             errorMsg = errorMessage;
2680                             return it;
2681 #endif
2682                         }
2683
2684                         SelectCommand(*itCommand);
2685
2686                         if (const auto &coroutine = GetCoroutine())
2687                         {
2688                             ++it;
2689                             RaiiSubparser coro(*this, std::vector<std::string>(it, end));
2690                             coroutine(coro.Parser());
2691 #ifdef ARGS_NOEXCEPT
2692                             error = GetError();
2693                             if (error != Error::None)
2694                             {
2695                                 return end;
2696                             }
2697
2698                             if (!coro.Parser().IsParsed())
2699                             {
2700                                 error = Error::Usage;
2701                                 return end;
2702                             }
2703 #else
2704                             if (!coro.Parser().IsParsed())
2705                             {
2706                                 throw UsageError("Subparser::Parse was not called");
2707                             }
2708 #endif
2709
2710                             break;
2711                         }
2712
2713                         commands = GetCommands();
2714                     } else
2715                     {
2716                         auto pos = GetNextPositional();
2717                         if (pos)
2718                         {
2719                             pos->ParseValue(chunk);
2720
2721                             if (pos->KickOut())
2722                             {
2723                                 return ++it;
2724                             }
2725                         } else
2726                         {
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);
2730 #else
2731                             error = Error::Parse;
2732                             errorMsg = errorMessage;
2733                             return it;
2734 #endif
2735                         }
2736                     }
2737
2738                     if (!readCompletion && completion != nullptr && completion->Matched())
2739                     {
2740 #ifdef ARGS_NOEXCEPT
2741                         error = Error::Completion;
2742 #endif
2743                         readCompletion = true;
2744                         ++it;
2745                         const auto argsLeft = static_cast<size_t>(std::distance(it, end));
2746                         if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft)
2747                         {
2748 #ifndef ARGS_NOEXCEPT
2749                             throw Completion("");
2750 #endif
2751                         }
2752
2753                         std::vector<std::string> curArgs(++it, end);
2754                         curArgs.resize(completion->cword);
2755
2756                         if (completion->syntax == "bash")
2757                         {
2758                             // bash tokenizes --flag=value as --flag=value
2759                             for (size_t idx = 0; idx < curArgs.size(); )
2760                             {
2761                                 if (idx > 0 && curArgs[idx] == "=")
2762                                 {
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())
2767                                     {
2768                                         curArgs[idx - 1] += curArgs[idx + 1];
2769                                         curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2);
2770                                     } else
2771                                     {
2772                                         curArgs.erase(curArgs.begin() + signedIdx);
2773                                     }
2774                                 } else
2775                                 {
2776                                     ++idx;
2777                                 }
2778                             }
2779
2780                         }
2781 #ifndef ARGS_NOEXCEPT
2782                         try
2783                         {
2784                             Parse(curArgs.begin(), curArgs.end());
2785                             throw Completion("");
2786                         }
2787                         catch (Completion &)
2788                         {
2789                             throw;
2790                         }
2791                         catch (args::Error&)
2792                         {
2793                             throw Completion("");
2794                         }
2795 #else
2796                         return Parse(curArgs.begin(), curArgs.end());
2797 #endif
2798                     }
2799                 }
2800
2801                 Validate(shortprefix, longprefix);
2802                 return end;
2803             }
2804
2805         public:
2806             HelpParams helpParams;
2807
2808             ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string())
2809             {
2810                 Description(description_);
2811                 Epilog(epilog_);
2812                 LongPrefix("--");
2813                 ShortPrefix("-");
2814                 LongSeparator("=");
2815                 Terminator("--");
2816                 SetArgumentSeparations(true, true, true, true);
2817                 matched = true;
2818             }
2819
2820             void AddCompletion(CompletionFlag &completionFlag)
2821             {
2822                 completion = &completionFlag;
2823                 Add(completionFlag);
2824             }
2825
2826             /** The program name for help generation
2827              */
2828             const std::string &Prog() const
2829             { return helpParams.programName; }
2830             /** The program name for help generation
2831              */
2832             void Prog(const std::string &prog_)
2833             { this->helpParams.programName = prog_; }
2834
2835             /** The prefix for long flags
2836              */
2837             const std::string &LongPrefix() const
2838             { return longprefix; }
2839             /** The prefix for long flags
2840              */
2841             void LongPrefix(const std::string &longprefix_)
2842             {
2843                 this->longprefix = longprefix_;
2844                 this->helpParams.longPrefix = longprefix_;
2845             }
2846
2847             /** The prefix for short flags
2848              */
2849             const std::string &ShortPrefix() const
2850             { return shortprefix; }
2851             /** The prefix for short flags
2852              */
2853             void ShortPrefix(const std::string &shortprefix_)
2854             {
2855                 this->shortprefix = shortprefix_;
2856                 this->helpParams.shortPrefix = shortprefix_;
2857             }
2858
2859             /** The separator for long flags
2860              */
2861             const std::string &LongSeparator() const
2862             { return longseparator; }
2863             /** The separator for long flags
2864              */
2865             void LongSeparator(const std::string &longseparator_)
2866             {
2867                 if (longseparator_.empty())
2868                 {
2869                     const std::string errorMessage("longseparator can not be set to empty");
2870 #ifdef ARGS_NOEXCEPT
2871                     error = Error::Usage;
2872                     errorMsg = errorMessage;
2873 #else
2874                     throw UsageError(errorMessage);
2875 #endif
2876                 } else
2877                 {
2878                     this->longseparator = longseparator_;
2879                     this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " ";
2880                 }
2881             }
2882
2883             /** The terminator that forcibly separates flags from positionals
2884              */
2885             const std::string &Terminator() const
2886             { return terminator; }
2887             /** The terminator that forcibly separates flags from positionals
2888              */
2889             void Terminator(const std::string &terminator_)
2890             { this->terminator = terminator_; }
2891
2892             /** Get the current argument separation parameters.
2893              *
2894              * See SetArgumentSeparations for details on what each one means.
2895              */
2896             void GetArgumentSeparations(
2897                 bool &allowJoinedShortValue_,
2898                 bool &allowJoinedLongValue_,
2899                 bool &allowSeparateShortValue_,
2900                 bool &allowSeparateLongValue_) const
2901             {
2902                 allowJoinedShortValue_ = this->allowJoinedShortValue;
2903                 allowJoinedLongValue_ = this->allowJoinedLongValue;
2904                 allowSeparateShortValue_ = this->allowSeparateShortValue;
2905                 allowSeparateLongValue_ = this->allowSeparateLongValue;
2906             }
2907
2908             /** Change allowed option separation.
2909              *
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)
2914              */
2915             void SetArgumentSeparations(
2916                 const bool allowJoinedShortValue_,
2917                 const bool allowJoinedLongValue_,
2918                 const bool allowSeparateShortValue_,
2919                 const bool allowSeparateLongValue_)
2920             {
2921                 this->allowJoinedShortValue = allowJoinedShortValue_;
2922                 this->allowJoinedLongValue = allowJoinedLongValue_;
2923                 this->allowSeparateShortValue = allowSeparateShortValue_;
2924                 this->allowSeparateLongValue = allowSeparateLongValue_;
2925
2926                 this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " ";
2927                 this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " ";
2928             }
2929
2930             /** Pass the help menu into an ostream
2931              */
2932             void Help(std::ostream &help_) const
2933             {
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);
2938
2939                 const bool hasoptions = command.HasFlag();
2940                 const bool hasarguments = command.HasPositional();
2941
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());
2947
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))
2953                 {
2954                     help_ << std::string(helpParams.progindent, ' ') << *progit << '\n';
2955                     ++progit;
2956                 }
2957                 for (; progit != std::end(proglines); ++progit)
2958                 {
2959                     help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n';
2960                 }
2961
2962                 help_ << '\n';
2963
2964                 if (!description_text.empty())
2965                 {
2966                     for (const auto &line: description_text)
2967                     {
2968                         help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
2969                     }
2970                     help_ << "\n";
2971                 }
2972
2973                 bool lastDescriptionIsNewline = false;
2974
2975                 if (!helpParams.optionsString.empty())
2976                 {
2977                     help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n";
2978                 }
2979
2980                 for (const auto &desc: command.GetDescription(helpParams, 0))
2981                 {
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));
2986
2987                     std::string::size_type flagssize = 0;
2988                     for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit)
2989                     {
2990                         if (flagsit != std::begin(flags))
2991                         {
2992                             help_ << '\n';
2993                         }
2994                         help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit;
2995                         flagssize = Glyphs(*flagsit);
2996                     }
2997
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)
3001                     {
3002                         help_ << '\n';
3003                     } else
3004                     {
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';
3007                         ++infoit;
3008                     }
3009                     for (; infoit != std::end(info); ++infoit)
3010                     {
3011                         help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n';
3012                     }
3013                 }
3014                 if (hasoptions && hasarguments && helpParams.showTerminator)
3015                 {
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))
3018                     {
3019                         help_ << std::string(helpParams.flagindent, ' ') << item << '\n';
3020                     }
3021                 }
3022
3023                 if (!lastDescriptionIsNewline)
3024                 {
3025                     help_ << "\n";
3026                 }
3027
3028                 for (const auto &line: epilog_text)
3029                 {
3030                     help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
3031                 }
3032             }
3033
3034             /** Generate a help menu as a string.
3035              *
3036              * \return the help text as a single string
3037              */
3038             std::string Help() const
3039             {
3040                 std::ostringstream help_;
3041                 Help(help_);
3042                 return help_.str();
3043             }
3044
3045             virtual void Reset() noexcept override
3046             {
3047                 Command::Reset();
3048                 matched = true;
3049                 readCompletion = false;
3050             }
3051
3052             /** Parse all arguments.
3053              *
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
3057              */
3058             template <typename It>
3059             It ParseArgs(It begin, It end)
3060             {
3061                 // Reset all Matched statuses and errors
3062                 Reset();
3063 #ifdef ARGS_NOEXCEPT
3064                 error = GetError();
3065                 if (error != Error::None)
3066                 {
3067                     return end;
3068                 }
3069 #endif
3070                 return Parse(begin, end);
3071             }
3072
3073             /** Parse all arguments.
3074              *
3075              * \param args an iterable of the arguments
3076              * \return the iterator after the last parsed value.  Only useful for kick-out
3077              */
3078             template <typename T>
3079             auto ParseArgs(const T &args) -> decltype(std::begin(args))
3080             {
3081                 return ParseArgs(std::begin(args), std::end(args));
3082             }
3083
3084             /** Convenience function to parse the CLI from argc and argv
3085              *
3086              * Just assigns the program name and vectorizes arguments for passing into ParseArgs()
3087              *
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.
3089              */
3090             bool ParseCLI(const int argc, const char * const * argv)
3091             {
3092                 if (Prog().empty())
3093                 {
3094                     Prog(argv[0]);
3095                 }
3096                 const std::vector<std::string> args(argv + 1, argv + argc);
3097                 return ParseArgs(args) == std::end(args);
3098             }
3099             
3100             template <typename T>
3101             bool ParseCLI(const T &args)
3102             {
3103                 return ParseArgs(args) == std::end(args);
3104             }
3105     };
3106
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)
3109     {
3110         command.subparser = &parser;
3111     }
3112
3113     inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams &params_): command(command_), parser(command, params_), oldSubparser(command.subparser)
3114     {
3115         command.subparser = &parser;
3116     }
3117
3118     inline void Subparser::Parse()
3119     {
3120         isParsed = true;
3121         Reset();
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)
3128         {
3129 #ifndef ARGS_NOEXCEPT
3130             throw args::SubparserError();
3131 #else
3132             error = Error::Subparser;
3133             return;
3134 #endif
3135         }
3136
3137         auto it = parser->Parse(args.begin(), args.end());
3138         command.Validate(parser->ShortPrefix(), parser->LongPrefix());
3139         kicked.assign(it, args.end());
3140
3141 #ifdef ARGS_NOEXCEPT
3142         command.subparserError = GetError();
3143 #endif
3144     }
3145
3146     inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser)
3147     {
3148         parser.Help(os);
3149         return os;
3150     }
3151
3152     /** Boolean argument matcher
3153      */
3154     class Flag : public FlagBase
3155     {
3156         public:
3157             Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_)
3158             {
3159                 group_.Add(*this);
3160             }
3161
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)
3163             {
3164             }
3165
3166             virtual ~Flag() {}
3167
3168             /** Get whether this was matched
3169              */
3170             bool Get() const
3171             {
3172                 return Matched();
3173             }
3174
3175             virtual Nargs NumberOfArguments() const noexcept override
3176             {
3177                 return 0;
3178             }
3179
3180             virtual void ParseValue(const std::vector<std::string>&) override
3181             {
3182             }
3183     };
3184
3185     /** Help flag class
3186      *
3187      * Works like a regular flag, but throws an instance of Help when it is matched
3188      */
3189     class HelpFlag : public Flag
3190     {
3191         public:
3192             HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {}
3193
3194             virtual ~HelpFlag() {}
3195
3196             virtual void ParseValue(const std::vector<std::string> &)
3197             {
3198 #ifdef ARGS_NOEXCEPT
3199                     error = Error::Help;
3200                     errorMsg = Name();
3201 #else
3202                     throw Help(Name());
3203 #endif
3204             }
3205
3206             /** Get whether this was matched
3207              */
3208             bool Get() const noexcept
3209             {
3210                 return Matched();
3211             }
3212     };
3213
3214     /** A flag class that simply counts the number of times it's matched
3215      */
3216     class CounterFlag : public Flag
3217     {
3218         private:
3219             const int startcount;
3220             int count;
3221
3222         public:
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_) {}
3225
3226             virtual ~CounterFlag() {}
3227
3228             virtual FlagBase *Match(const EitherFlag &arg) override
3229             {
3230                 auto me = FlagBase::Match(arg);
3231                 if (me)
3232                 {
3233                     ++count;
3234                 }
3235                 return me;
3236             }
3237
3238             /** Get the count
3239              */
3240             int &Get() noexcept
3241             {
3242                 return count;
3243             }
3244
3245             int &operator *() noexcept {
3246                 return count;
3247             }
3248             
3249             const int &operator *() const noexcept {
3250                 return count;
3251             }
3252
3253             virtual void Reset() noexcept override
3254             {
3255                 FlagBase::Reset();
3256                 count = startcount;
3257             }
3258     };
3259
3260     /** A flag class that calls a function when it's matched
3261      */
3262     class ActionFlag : public FlagBase
3263     {
3264         private:
3265             std::function<void(const std::vector<std::string> &)> action;
3266             Nargs nargs;
3267
3268         public:
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_)
3271             {
3272                 group_.Add(*this);
3273             }
3274
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)
3277             {
3278                 group_.Add(*this);
3279                 action = [action_](const std::vector<std::string> &a) { return action_(a.at(0)); };
3280             }
3281
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)
3284             {
3285                 group_.Add(*this);
3286                 action = [action_](const std::vector<std::string> &) { return action_(); };
3287             }
3288
3289             virtual Nargs NumberOfArguments() const noexcept override
3290             { return nargs; }
3291
3292             virtual void ParseValue(const std::vector<std::string> &value) override
3293             { action(value); }
3294     };
3295
3296     /** A default Reader class for argument classes
3297      *
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.
3301      */
3302     struct ValueReader
3303     {
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)
3307         {
3308             std::istringstream ss(value);
3309             bool failed = !(ss >> destination);
3310
3311             if (!failed)
3312             {
3313                 ss >> std::ws;
3314             }
3315
3316             if (ss.rdbuf()->in_avail() > 0 || failed)
3317             {
3318 #ifdef ARGS_NOEXCEPT
3319                 (void)name;
3320                 return false;
3321 #else
3322                 std::ostringstream problem;
3323                 problem << "Argument '" << name << "' received invalid value type '" << value << "'";
3324                 throw ParseError(problem.str());
3325 #endif
3326             }
3327             return true;
3328         }
3329
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)
3333         {
3334             destination = value;
3335             return true;
3336         }
3337     };
3338
3339     /** An argument-accepting flag class
3340      * 
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)
3343      */
3344     template <
3345         typename T,
3346         typename Reader = ValueReader>
3347     class ValueFlag : public ValueFlagBase
3348     {
3349         protected:
3350             T value;
3351             T defaultValue;
3352
3353             virtual std::string GetDefaultString(const HelpParams&) const override
3354             {
3355                 return detail::ToString(defaultValue);
3356             }
3357
3358         private:
3359             Reader reader;
3360
3361         public:
3362
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_)
3364             {
3365                 group_.Add(*this);
3366             }
3367
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)
3369             {
3370             }
3371
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_)
3373             {
3374             }
3375
3376             virtual ~ValueFlag() {}
3377
3378             virtual void ParseValue(const std::vector<std::string> &values_) override
3379             {
3380                 const std::string &value_ = values_.at(0);
3381
3382 #ifdef ARGS_NOEXCEPT
3383                 if (!reader(name, value_, this->value))
3384                 {
3385                     error = Error::Parse;
3386                 }
3387 #else
3388                 reader(name, value_, this->value);
3389 #endif
3390             }
3391
3392             virtual void Reset() noexcept override
3393             {
3394                 ValueFlagBase::Reset();
3395                 value = defaultValue;
3396             }
3397
3398             /** Get the value
3399              */
3400             T &Get() noexcept
3401             {
3402                 return value;
3403             }
3404
3405             /** Get the value
3406              */
3407             T &operator *() noexcept
3408             {
3409                 return value;
3410             }
3411
3412             /** Get the value
3413              */
3414             const T &operator *() const noexcept
3415             {
3416                 return value;
3417             }
3418
3419             /** Get the value
3420              */
3421             T *operator ->() noexcept
3422             {
3423                 return &value;
3424             }
3425
3426             /** Get the value
3427              */
3428             const T *operator ->() const noexcept
3429             {
3430                 return &value;
3431             }
3432
3433             /** Get the default value
3434              */
3435             const T &GetDefault() noexcept
3436             {
3437                 return defaultValue;
3438             }
3439     };
3440
3441     /** An optional argument-accepting flag class
3442      *
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)
3445      */
3446     template <
3447         typename T,
3448         typename Reader = ValueReader>
3449     class ImplicitValueFlag : public ValueFlag<T, Reader>
3450     {
3451         protected:
3452             T implicitValue;
3453
3454         public:
3455
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_)
3458             {
3459             }
3460
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_)
3463             {
3464             }
3465
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()
3468             {
3469             }
3470
3471             virtual ~ImplicitValueFlag() {}
3472
3473             virtual Nargs NumberOfArguments() const noexcept override
3474             {
3475                 return {0, 1};
3476             }
3477
3478             virtual void ParseValue(const std::vector<std::string> &value_) override
3479             {
3480                 if (value_.empty())
3481                 {
3482                     this->value = implicitValue;
3483                 } else
3484                 {
3485                     ValueFlag<T, Reader>::ParseValue(value_);
3486                 }
3487             }
3488     };
3489
3490     /** A variadic arguments accepting flag class
3491      *
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)
3495      */
3496     template <
3497         typename T,
3498         template <typename...> class List = detail::vector,
3499         typename Reader = ValueReader>
3500     class NargsValueFlag : public FlagBase
3501     {
3502         protected:
3503
3504             List<T> values;
3505             const List<T> defaultValues;
3506             Nargs nargs;
3507             Reader reader;
3508
3509         public:
3510
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;
3524
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_)
3527             {
3528                 group_.Add(*this);
3529             }
3530
3531             virtual ~NargsValueFlag() {}
3532
3533             virtual Nargs NumberOfArguments() const noexcept override
3534             {
3535                 return nargs;
3536             }
3537
3538             virtual void ParseValue(const std::vector<std::string> &values_) override
3539             {
3540                 values.clear();
3541
3542                 for (const std::string &value : values_)
3543                 {
3544                     T v;
3545 #ifdef ARGS_NOEXCEPT
3546                     if (!reader(name, value, v))
3547                     {
3548                         error = Error::Parse;
3549                     }
3550 #else
3551                     reader(name, value, v);
3552 #endif
3553                     values.insert(std::end(values), v);
3554                 }
3555             }
3556
3557             List<T> &Get() noexcept
3558             {
3559                 return values;
3560             }
3561
3562             /** Get the value
3563              */
3564             List<T> &operator *() noexcept
3565             {
3566                 return values;
3567             }
3568
3569             /** Get the values
3570              */
3571             const List<T> &operator *() const noexcept
3572             {
3573                 return values;
3574             }
3575
3576             /** Get the values
3577              */
3578             List<T> *operator ->() noexcept
3579             {
3580                 return &values;
3581             }
3582
3583             /** Get the values
3584              */
3585             const List<T> *operator ->() const noexcept
3586             {
3587                 return &values;
3588             }
3589
3590             iterator begin() noexcept
3591             {
3592                 return values.begin();
3593             }
3594
3595             const_iterator begin() const noexcept
3596             {
3597                 return values.begin();
3598             }
3599
3600             const_iterator cbegin() const noexcept
3601             {
3602                 return values.cbegin();
3603             }
3604
3605             iterator end() noexcept
3606             {
3607                 return values.end();
3608             }
3609
3610             const_iterator end() const noexcept 
3611             {
3612                 return values.end();
3613             }
3614
3615             const_iterator cend() const noexcept
3616             {
3617                 return values.cend();
3618             }
3619
3620             virtual void Reset() noexcept override
3621             {
3622                 FlagBase::Reset();
3623                 values = defaultValues;
3624             }
3625
3626             virtual FlagBase *Match(const EitherFlag &arg) override
3627             {
3628                 const bool wasMatched = Matched();
3629                 auto me = FlagBase::Match(arg);
3630                 if (me && !wasMatched)
3631                 {
3632                     values.clear();
3633                 }
3634                 return me;
3635             }
3636     };
3637
3638     /** An argument-accepting flag class that pushes the found values into a list
3639      * 
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)
3643      */
3644     template <
3645         typename T,
3646         template <typename...> class List = detail::vector,
3647         typename Reader = ValueReader>
3648     class ValueFlagList : public ValueFlagBase
3649     {
3650         private:
3651             using Container = List<T>;
3652             Container values;
3653             const Container defaultValues;
3654             Reader reader;
3655
3656         public:
3657
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;
3670
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_)
3673             {
3674                 group_.Add(*this);
3675             }
3676
3677             virtual ~ValueFlagList() {}
3678
3679             virtual void ParseValue(const std::vector<std::string> &values_) override
3680             {
3681                 const std::string &value_ = values_.at(0);
3682
3683                 T v;
3684 #ifdef ARGS_NOEXCEPT
3685                 if (!reader(name, value_, v))
3686                 {
3687                     error = Error::Parse;
3688                 }
3689 #else
3690                 reader(name, value_, v);
3691 #endif
3692                 values.insert(std::end(values), v);
3693             }
3694
3695             /** Get the values
3696              */
3697             Container &Get() noexcept
3698             {
3699                 return values;
3700             }
3701
3702             /** Get the value
3703              */
3704             Container &operator *() noexcept
3705             {
3706                 return values;
3707             }
3708
3709             /** Get the values
3710              */
3711             const Container &operator *() const noexcept
3712             {
3713                 return values;
3714             }
3715
3716             /** Get the values
3717              */
3718             Container *operator ->() noexcept
3719             {
3720                 return &values;
3721             }
3722
3723             /** Get the values
3724              */
3725             const Container *operator ->() const noexcept
3726             {
3727                 return &values;
3728             }
3729
3730             virtual std::string Name() const override
3731             {
3732                 return name + std::string("...");
3733             }
3734
3735             virtual void Reset() noexcept override
3736             {
3737                 ValueFlagBase::Reset();
3738                 values = defaultValues;
3739             }
3740
3741             virtual FlagBase *Match(const EitherFlag &arg) override
3742             {
3743                 const bool wasMatched = Matched();
3744                 auto me = FlagBase::Match(arg);
3745                 if (me && !wasMatched)
3746                 {
3747                     values.clear();
3748                 }
3749                 return me;
3750             }
3751
3752             iterator begin() noexcept
3753             {
3754                 return values.begin();
3755             }
3756
3757             const_iterator begin() const noexcept
3758             {
3759                 return values.begin();
3760             }
3761
3762             const_iterator cbegin() const noexcept
3763             {
3764                 return values.cbegin();
3765             }
3766
3767             iterator end() noexcept
3768             {
3769                 return values.end();
3770             }
3771
3772             const_iterator end() const noexcept 
3773             {
3774                 return values.end();
3775             }
3776
3777             const_iterator cend() const noexcept
3778             {
3779                 return values.cend();
3780             }
3781     };
3782
3783     /** A mapping value flag class
3784      * 
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
3789      */
3790     template <
3791         typename K,
3792         typename T,
3793         typename Reader = ValueReader,
3794         template <typename...> class Map = detail::unordered_map>
3795     class MapFlag : public ValueFlagBase
3796     {
3797         private:
3798             const Map<K, T> map;
3799             T value;
3800             const T defaultValue;
3801             Reader reader;
3802
3803         protected:
3804             virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3805             {
3806                 return detail::MapKeysToStrings(map);
3807             }
3808
3809         public:
3810
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_)
3812             {
3813                 group_.Add(*this);
3814             }
3815
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)
3817             {
3818             }
3819
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_)
3821             {
3822             }
3823
3824             virtual ~MapFlag() {}
3825
3826             virtual void ParseValue(const std::vector<std::string> &values_) override
3827             {
3828                 const std::string &value_ = values_.at(0);
3829
3830                 K key;
3831 #ifdef ARGS_NOEXCEPT
3832                 if (!reader(name, value_, key))
3833                 {
3834                     error = Error::Parse;
3835                 }
3836 #else
3837                 reader(name, value_, key);
3838 #endif
3839                 auto it = map.find(key);
3840                 if (it == std::end(map))
3841                 {
3842                     std::ostringstream problem;
3843                     problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3844 #ifdef ARGS_NOEXCEPT
3845                     error = Error::Map;
3846                     errorMsg = problem.str();
3847 #else
3848                     throw MapError(problem.str());
3849 #endif
3850                 } else
3851                 {
3852                     this->value = it->second;
3853                 }
3854             }
3855
3856             /** Get the value
3857              */
3858             T &Get() noexcept
3859             {
3860                 return value;
3861             }
3862
3863             /** Get the value
3864              */
3865             T &operator *() noexcept
3866             {
3867                 return value;
3868             }
3869
3870             /** Get the value
3871              */
3872             const T &operator *() const noexcept
3873             {
3874                 return value;
3875             }
3876
3877             /** Get the value
3878              */
3879             T *operator ->() noexcept
3880             {
3881                 return &value;
3882             }
3883
3884             /** Get the value
3885              */
3886             const T *operator ->() const noexcept
3887             {
3888                 return &value;
3889             }
3890
3891             virtual void Reset() noexcept override
3892             {
3893                 ValueFlagBase::Reset();
3894                 value = defaultValue;
3895             }
3896     };
3897
3898     /** A mapping value flag list class
3899      * 
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
3905      */
3906     template <
3907         typename K,
3908         typename T,
3909         template <typename...> class List = detail::vector,
3910         typename Reader = ValueReader,
3911         template <typename...> class Map = detail::unordered_map>
3912     class MapFlagList : public ValueFlagBase
3913     {
3914         private:
3915             using Container = List<T>;
3916             const Map<K, T> map;
3917             Container values;
3918             const Container defaultValues;
3919             Reader reader;
3920
3921         protected:
3922             virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3923             {
3924                 return detail::MapKeysToStrings(map);
3925             }
3926
3927         public:
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;
3940
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_)
3942             {
3943                 group_.Add(*this);
3944             }
3945
3946             virtual ~MapFlagList() {}
3947
3948             virtual void ParseValue(const std::vector<std::string> &values_) override
3949             {
3950                 const std::string &value = values_.at(0);
3951
3952                 K key;
3953 #ifdef ARGS_NOEXCEPT
3954                 if (!reader(name, value, key))
3955                 {
3956                     error = Error::Parse;
3957                 }
3958 #else
3959                 reader(name, value, key);
3960 #endif
3961                 auto it = map.find(key);
3962                 if (it == std::end(map))
3963                 {
3964                     std::ostringstream problem;
3965                     problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3966 #ifdef ARGS_NOEXCEPT
3967                     error = Error::Map;
3968                     errorMsg = problem.str();
3969 #else
3970                     throw MapError(problem.str());
3971 #endif
3972                 } else
3973                 {
3974                     this->values.emplace_back(it->second);
3975                 }
3976             }
3977
3978             /** Get the value
3979              */
3980             Container &Get() noexcept
3981             {
3982                 return values;
3983             }
3984
3985             /** Get the value
3986              */
3987             Container &operator *() noexcept
3988             {
3989                 return values;
3990             }
3991
3992             /** Get the values
3993              */
3994             const Container &operator *() const noexcept
3995             {
3996                 return values;
3997             }
3998
3999             /** Get the values
4000              */
4001             Container *operator ->() noexcept
4002             {
4003                 return &values;
4004             }
4005
4006             /** Get the values
4007              */
4008             const Container *operator ->() const noexcept
4009             {
4010                 return &values;
4011             }
4012
4013             virtual std::string Name() const override
4014             {
4015                 return name + std::string("...");
4016             }
4017
4018             virtual void Reset() noexcept override
4019             {
4020                 ValueFlagBase::Reset();
4021                 values = defaultValues;
4022             }
4023
4024             virtual FlagBase *Match(const EitherFlag &arg) override
4025             {
4026                 const bool wasMatched = Matched();
4027                 auto me = FlagBase::Match(arg);
4028                 if (me && !wasMatched)
4029                 {
4030                     values.clear();
4031                 }
4032                 return me;
4033             }
4034
4035             iterator begin() noexcept
4036             {
4037                 return values.begin();
4038             }
4039
4040             const_iterator begin() const noexcept
4041             {
4042                 return values.begin();
4043             }
4044
4045             const_iterator cbegin() const noexcept
4046             {
4047                 return values.cbegin();
4048             }
4049
4050             iterator end() noexcept
4051             {
4052                 return values.end();
4053             }
4054
4055             const_iterator end() const noexcept 
4056             {
4057                 return values.end();
4058             }
4059
4060             const_iterator cend() const noexcept
4061             {
4062                 return values.cend();
4063             }
4064     };
4065
4066     /** A positional argument class
4067      *
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)
4070      */
4071     template <
4072         typename T,
4073         typename Reader = ValueReader>
4074     class Positional : public PositionalBase
4075     {
4076         private:
4077             T value;
4078             const T defaultValue;
4079             Reader reader;
4080         public:
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_)
4082             {
4083                 group_.Add(*this);
4084             }
4085
4086             Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_)
4087             {
4088             }
4089
4090             virtual ~Positional() {}
4091
4092             virtual void ParseValue(const std::string &value_) override
4093             {
4094 #ifdef ARGS_NOEXCEPT
4095                 if (!reader(name, value_, this->value))
4096                 {
4097                     error = Error::Parse;
4098                 }
4099 #else
4100                 reader(name, value_, this->value);
4101 #endif
4102                 ready = false;
4103                 matched = true;
4104             }
4105
4106             /** Get the value
4107              */
4108             T &Get() noexcept
4109             {
4110                 return value;
4111             }
4112
4113             /** Get the value
4114              */
4115             T &operator *() noexcept
4116             {
4117                 return value;
4118             }
4119
4120             /** Get the value
4121              */
4122             const T &operator *() const noexcept
4123             {
4124                 return value;
4125             }
4126
4127             /** Get the value
4128              */
4129             T *operator ->() noexcept
4130             {
4131                 return &value;
4132             }
4133
4134             /** Get the value
4135              */
4136             const T *operator ->() const noexcept
4137             {
4138                 return &value;
4139             }
4140
4141             virtual void Reset() noexcept override
4142             {
4143                 PositionalBase::Reset();
4144                 value = defaultValue;
4145             }
4146     };
4147
4148     /** A positional argument class that pushes the found values into a list
4149      * 
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)
4153      */
4154     template <
4155         typename T,
4156         template <typename...> class List = detail::vector,
4157         typename Reader = ValueReader>
4158     class PositionalList : public PositionalBase
4159     {
4160         private:
4161             using Container = List<T>;
4162             Container values;
4163             const Container defaultValues;
4164             Reader reader;
4165
4166         public:
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;
4179
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_)
4181             {
4182                 group_.Add(*this);
4183             }
4184
4185             PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_)
4186             {
4187             }
4188
4189             virtual ~PositionalList() {}
4190
4191             virtual void ParseValue(const std::string &value_) override
4192             {
4193                 T v;
4194 #ifdef ARGS_NOEXCEPT
4195                 if (!reader(name, value_, v))
4196                 {
4197                     error = Error::Parse;
4198                 }
4199 #else
4200                 reader(name, value_, v);
4201 #endif
4202                 values.insert(std::end(values), v);
4203                 matched = true;
4204             }
4205
4206             virtual std::string Name() const override
4207             {
4208                 return name + std::string("...");
4209             }
4210
4211             /** Get the values
4212              */
4213             Container &Get() noexcept
4214             {
4215                 return values;
4216             }
4217
4218             /** Get the value
4219              */
4220             Container &operator *() noexcept
4221             {
4222                 return values;
4223             }
4224
4225             /** Get the values
4226              */
4227             const Container &operator *() const noexcept
4228             {
4229                 return values;
4230             }
4231
4232             /** Get the values
4233              */
4234             Container *operator ->() noexcept
4235             {
4236                 return &values;
4237             }
4238
4239             /** Get the values
4240              */
4241             const Container *operator ->() const noexcept
4242             {
4243                 return &values;
4244             }
4245
4246             virtual void Reset() noexcept override
4247             {
4248                 PositionalBase::Reset();
4249                 values = defaultValues;
4250             }
4251
4252             virtual PositionalBase *GetNextPositional() override
4253             {
4254                 const bool wasMatched = Matched();
4255                 auto me = PositionalBase::GetNextPositional();
4256                 if (me && !wasMatched)
4257                 {
4258                     values.clear();
4259                 }
4260                 return me;
4261             }
4262
4263             iterator begin() noexcept
4264             {
4265                 return values.begin();
4266             }
4267
4268             const_iterator begin() const noexcept
4269             {
4270                 return values.begin();
4271             }
4272
4273             const_iterator cbegin() const noexcept
4274             {
4275                 return values.cbegin();
4276             }
4277
4278             iterator end() noexcept
4279             {
4280                 return values.end();
4281             }
4282
4283             const_iterator end() const noexcept 
4284             {
4285                 return values.end();
4286             }
4287
4288             const_iterator cend() const noexcept
4289             {
4290                 return values.cend();
4291             }
4292     };
4293
4294     /** A positional argument mapping class
4295      * 
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
4300      */
4301     template <
4302         typename K,
4303         typename T,
4304         typename Reader = ValueReader,
4305         template <typename...> class Map = detail::unordered_map>
4306     class MapPositional : public PositionalBase
4307     {
4308         private:
4309             const Map<K, T> map;
4310             T value;
4311             const T defaultValue;
4312             Reader reader;
4313
4314         protected:
4315             virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4316             {
4317                 return detail::MapKeysToStrings(map);
4318             }
4319
4320         public:
4321
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_)
4324             {
4325                 group_.Add(*this);
4326             }
4327
4328             virtual ~MapPositional() {}
4329
4330             virtual void ParseValue(const std::string &value_) override
4331             {
4332                 K key;
4333 #ifdef ARGS_NOEXCEPT
4334                 if (!reader(name, value_, key))
4335                 {
4336                     error = Error::Parse;
4337                 }
4338 #else
4339                 reader(name, value_, key);
4340 #endif
4341                 auto it = map.find(key);
4342                 if (it == std::end(map))
4343                 {
4344                     std::ostringstream problem;
4345                     problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4346 #ifdef ARGS_NOEXCEPT
4347                     error = Error::Map;
4348                     errorMsg = problem.str();
4349 #else
4350                     throw MapError(problem.str());
4351 #endif
4352                 } else
4353                 {
4354                     this->value = it->second;
4355                     ready = false;
4356                     matched = true;
4357                 }
4358             }
4359
4360             /** Get the value
4361              */
4362             T &Get() noexcept
4363             {
4364                 return value;
4365             }
4366
4367             /** Get the value
4368              */
4369             T &operator *() noexcept
4370             {
4371                 return value;
4372             }
4373
4374             /** Get the value
4375              */
4376             const T &operator *() const noexcept
4377             {
4378                 return value;
4379             }
4380
4381             /** Get the value
4382              */
4383             T *operator ->() noexcept
4384             {
4385                 return &value;
4386             }
4387
4388             /** Get the value
4389              */
4390             const T *operator ->() const noexcept
4391             {
4392                 return &value;
4393             }
4394
4395             virtual void Reset() noexcept override
4396             {
4397                 PositionalBase::Reset();
4398                 value = defaultValue;
4399             }
4400     };
4401
4402     /** A positional argument mapping list class
4403      * 
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
4409      */
4410     template <
4411         typename K,
4412         typename T,
4413         template <typename...> class List = detail::vector,
4414         typename Reader = ValueReader,
4415         template <typename...> class Map = detail::unordered_map>
4416     class MapPositionalList : public PositionalBase
4417     {
4418         private:
4419             using Container = List<T>;
4420
4421             const Map<K, T> map;
4422             Container values;
4423             const Container defaultValues;
4424             Reader reader;
4425
4426         protected:
4427             virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4428             {
4429                 return detail::MapKeysToStrings(map);
4430             }
4431
4432         public:
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;
4445
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_)
4448             {
4449                 group_.Add(*this);
4450             }
4451
4452             virtual ~MapPositionalList() {}
4453
4454             virtual void ParseValue(const std::string &value_) override
4455             {
4456                 K key;
4457 #ifdef ARGS_NOEXCEPT
4458                 if (!reader(name, value_, key))
4459                 {
4460                     error = Error::Parse;
4461                 }
4462 #else
4463                 reader(name, value_, key);
4464 #endif
4465                 auto it = map.find(key);
4466                 if (it == std::end(map))
4467                 {
4468                     std::ostringstream problem;
4469                     problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4470 #ifdef ARGS_NOEXCEPT
4471                     error = Error::Map;
4472                     errorMsg = problem.str();
4473 #else
4474                     throw MapError(problem.str());
4475 #endif
4476                 } else
4477                 {
4478                     this->values.emplace_back(it->second);
4479                     matched = true;
4480                 }
4481             }
4482
4483             /** Get the value
4484              */
4485             Container &Get() noexcept
4486             {
4487                 return values;
4488             }
4489
4490             /** Get the value
4491              */
4492             Container &operator *() noexcept
4493             {
4494                 return values;
4495             }
4496
4497             /** Get the values
4498              */
4499             const Container &operator *() const noexcept
4500             {
4501                 return values;
4502             }
4503
4504             /** Get the values
4505              */
4506             Container *operator ->() noexcept
4507             {
4508                 return &values;
4509             }
4510
4511             /** Get the values
4512              */
4513             const Container *operator ->() const noexcept
4514             {
4515                 return &values;
4516             }
4517
4518             virtual std::string Name() const override
4519             {
4520                 return name + std::string("...");
4521             }
4522
4523             virtual void Reset() noexcept override
4524             {
4525                 PositionalBase::Reset();
4526                 values = defaultValues;
4527             }
4528
4529             virtual PositionalBase *GetNextPositional() override
4530             {
4531                 const bool wasMatched = Matched();
4532                 auto me = PositionalBase::GetNextPositional();
4533                 if (me && !wasMatched)
4534                 {
4535                     values.clear();
4536                 }
4537                 return me;
4538             }
4539
4540             iterator begin() noexcept
4541             {
4542                 return values.begin();
4543             }
4544
4545             const_iterator begin() const noexcept
4546             {
4547                 return values.begin();
4548             }
4549
4550             const_iterator cbegin() const noexcept
4551             {
4552                 return values.cbegin();
4553             }
4554
4555             iterator end() noexcept
4556             {
4557                 return values.end();
4558             }
4559
4560             const_iterator end() const noexcept 
4561             {
4562                 return values.end();
4563             }
4564
4565             const_iterator cend() const noexcept
4566             {
4567                 return values.cend();
4568             }
4569     };
4570 }
4571
4572 #endif