Coverage Report

Created: 2025-07-18 06:35

/src/args/args.hxx
Line
Count
Source (jump to first uncovered line)
1
/* A simple header-only C++ argument parser library.
2
 *
3
 * https://github.com/Taywee/args
4
 *
5
 * Copyright (c) 2016-2024 Taylor C. Richberger <taylor@axfive.net> 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.4.7"
37
#define ARGS_VERSION_MAJOR 6
38
#define ARGS_VERSION_MINOR 4
39
#define ARGS_VERSION_PATCH 7
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
0
    {
92
0
        std::string::size_type length = 0;
93
0
        for (const char c: string_)
94
0
        {
95
0
            if ((c & 0xc0) != 0x80)
96
0
            {
97
0
                ++length;
98
0
            }
99
0
        }
100
0
        return length;
101
0
    }
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
0
    {
121
0
        std::vector<std::string> output;
122
0
        std::string line(firstlineindent, ' ');
123
0
        bool empty = true;
124
0
125
0
        if (firstlinewidth == 0)
126
0
        {
127
0
            firstlinewidth = width;
128
0
        }
129
0
130
0
        auto currentwidth = firstlinewidth;
131
0
132
0
        for (auto it = begin; it != end; ++it)
133
0
        {
134
0
            if (it->empty())
135
0
            {
136
0
                continue;
137
0
            }
138
0
139
0
            if (*it == "\n")
140
0
            {
141
0
                if (!empty)
142
0
                {
143
0
                    output.push_back(line);
144
0
                    line.clear();
145
0
                    empty = true;
146
0
                    currentwidth = width;
147
0
                }
148
0
149
0
                continue;
150
0
            }
151
0
152
0
            auto itemsize = Glyphs(*it);
153
0
            if ((line.length() + 1 + itemsize) > currentwidth)
154
0
            {
155
0
                if (!empty)
156
0
                {
157
0
                    output.push_back(line);
158
0
                    line.clear();
159
0
                    empty = true;
160
0
                    currentwidth = width;
161
0
                }
162
0
            }
163
0
164
0
            if (itemsize > 0)
165
0
            {
166
0
                if (!empty)
167
0
                {
168
0
                    line += ' ';
169
0
                }
170
0
171
0
                line += *it;
172
0
                empty = false;
173
0
            }
174
0
        }
175
0
176
0
        if (!empty)
177
0
        {
178
0
            output.push_back(line);
179
0
        }
180
0
181
0
        return output;
182
0
    }
Unexecuted instantiation: std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > args::Wrap<std::__1::istream_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char, std::__1::char_traits<char>, long> >(std::__1::istream_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char, std::__1::char_traits<char>, long>, std::__1::istream_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char, std::__1::char_traits<char>, long>, unsigned long, unsigned long, unsigned long)
Unexecuted instantiation: std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > args::Wrap<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, unsigned long, unsigned long, unsigned long)
183
184
    namespace detail
185
    {
186
        template <typename T>
187
        std::string Join(const T& array, const std::string &delimiter)
188
0
        {
189
0
            std::string res;
190
0
            for (auto &element : array)
191
0
            {
192
0
                if (!res.empty())
193
0
                {
194
0
                    res += delimiter;
195
0
                }
196
197
0
                res += element;
198
0
            }
199
200
0
            return res;
201
0
        }
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
0
    {
215
0
        // Preserve existing line breaks
216
0
        const auto newlineloc = in.find('\n');
217
0
        if (newlineloc != in.npos)
218
0
        {
219
0
            auto first = Wrap(std::string(in, 0, newlineloc), width);
220
0
            auto second = Wrap(std::string(in, newlineloc + 1), width);
221
0
            first.insert(
222
0
                std::end(first),
223
0
                std::make_move_iterator(std::begin(second)),
224
0
                std::make_move_iterator(std::end(second)));
225
0
            return first;
226
0
        }
227
0
228
0
        std::istringstream stream(in);
229
0
        std::string::size_type indent = 0;
230
0
231
0
        for (auto c : in)
232
0
        {
233
0
            if (!std::isspace(static_cast<unsigned char>(c)))
234
0
            {
235
0
                break;
236
0
            }
237
0
            ++indent;
238
0
        }
239
0
240
0
        return Wrap(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>(),
241
0
                    width, firstlinewidth, indent);
242
0
    }
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
893
            Error(const std::string &problem) : std::runtime_error(problem) {}
266
0
            virtual ~Error() {}
267
    };
268
269
    /** Errors that occur during usage
270
     */
271
    class UsageError : public Error
272
    {
273
        public:
274
0
            UsageError(const std::string &problem) : Error(problem) {}
275
0
            virtual ~UsageError() {}
276
    };
277
278
    /** Errors that occur during regular parsing
279
     */
280
    class ParseError : public Error
281
    {
282
        public:
283
872
            ParseError(const std::string &problem) : Error(problem) {}
284
0
            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
0
            ValidationError(const std::string &problem) : Error(problem) {}
293
0
            virtual ~ValidationError() {}
294
    };
295
296
    /** Errors that when a required flag is omitted
297
     */
298
    class RequiredError : public ValidationError
299
    {
300
        public:
301
0
            RequiredError(const std::string &problem) : ValidationError(problem) {}
302
0
            virtual ~RequiredError() {}
303
    };
304
305
    /** Errors in map lookups
306
     */
307
    class MapError : public ParseError
308
    {
309
        public:
310
0
            MapError(const std::string &problem) : ParseError(problem) {}
311
0
            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
0
            ExtraError(const std::string &problem) : ParseError(problem) {}
320
0
            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
21
            Help(const std::string &flag) : Error(flag) {}
329
0
            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
0
            SubparserError() : Error("") {}
338
0
            virtual ~SubparserError() {}
339
    };
340
341
    /** An exception that contains autocompletion reply
342
     */
343
    class Completion : public Error
344
    {
345
        public:
346
0
            Completion(const std::string &flag) : Error(flag) {}
347
0
            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
538
        EitherFlag(const std::string &flag) : isShort(false), shortFlag(), longFlag(flag) {}
359
2.71k
        EitherFlag(const char *flag) : isShort(false), shortFlag(), longFlag(flag) {}
360
9.55k
        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
2.71k
        {
366
2.71k
            std::unordered_set<std::string>  longFlags;
367
2.71k
            for (const EitherFlag &flag: flags)
368
5.43k
            {
369
5.43k
                if (!flag.isShort)
370
2.71k
                {
371
2.71k
                    longFlags.insert(flag.longFlag);
372
2.71k
                }
373
5.43k
            }
374
2.71k
            return longFlags;
375
2.71k
        }
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
2.71k
        {
381
2.71k
            std::unordered_set<char>  shortFlags;
382
2.71k
            for (const EitherFlag &flag: flags)
383
5.43k
            {
384
5.43k
                if (flag.isShort)
385
2.71k
                {
386
2.71k
                    shortFlags.insert(flag.shortFlag);
387
2.71k
                }
388
5.43k
            }
389
2.71k
            return shortFlags;
390
2.71k
        }
391
392
        std::string str() const
393
0
        {
394
0
            return isShort ? std::string(1, shortFlag) : longFlag;
395
0
        }
396
397
        std::string str(const std::string &shortPrefix, const std::string &longPrefix) const
398
0
        {
399
0
            return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag;
400
0
        }
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
2.71k
                shortFlags(shortFlagsStart, shortFlagsEnd),
425
2.71k
                longFlags(longFlagsStart, longFlagsEnd)
426
2.71k
            {
427
2.71k
                if (shortFlags.empty() && longFlags.empty())
428
0
                {
429
0
#ifndef ARGS_NOEXCEPT
430
0
                    throw UsageError("empty Matcher");
431
0
#endif
432
0
                }
433
2.71k
            }
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
2.71k
                Matcher(std::begin(shortIn), std::end(shortIn), std::begin(longIn), std::end(longIn))
450
2.71k
            {}
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
2.71k
                Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {}
466
467
2.71k
            Matcher(Matcher &&other) noexcept : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags))
468
2.71k
            {}
469
470
5.43k
            ~Matcher() {}
471
472
            /** (INTERNAL) Check if there is a match of a short flag
473
             */
474
            bool Match(const char flag) const
475
17.9k
            {
476
17.9k
                return shortFlags.find(flag) != shortFlags.end();
477
17.9k
            }
478
479
            /** (INTERNAL) Check if there is a match of a long flag
480
             */
481
            bool Match(const std::string &flag) const
482
1.52k
            {
483
1.52k
                return longFlags.find(flag) != longFlags.end();
484
1.52k
            }
485
486
            /** (INTERNAL) Check if there is a match of a flag
487
             */
488
            bool Match(const EitherFlag &flag) const
489
19.5k
            {
490
19.5k
                return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag);
491
19.5k
            }
492
493
            /** (INTERNAL) Get all flag strings as a vector, with the prefixes embedded
494
             */
495
            std::vector<EitherFlag> GetFlagStrings() const
496
0
            {
497
0
                std::vector<EitherFlag> flagStrings;
498
0
                flagStrings.reserve(shortFlags.size() + longFlags.size());
499
0
                for (const char flag: shortFlags)
500
0
                {
501
0
                    flagStrings.emplace_back(flag);
502
0
                }
503
0
                for (const std::string &flag: longFlags)
504
0
                {
505
0
                    flagStrings.emplace_back(flag);
506
0
                }
507
0
                return flagStrings;
508
0
            }
509
510
            /** (INTERNAL) Get long flag if it exists or any short flag
511
             */
512
            EitherFlag GetLongOrAny() const
513
0
            {
514
0
                if (!longFlags.empty())
515
0
                {
516
0
                    return *longFlags.begin();
517
0
                }
518
519
0
                if (!shortFlags.empty())
520
0
                {
521
0
                    return *shortFlags.begin();
522
0
                }
523
524
                // should be unreachable
525
0
                return ' ';
526
0
            }
527
528
            /** (INTERNAL) Get short flag if it exists or any long flag
529
             */
530
            EitherFlag GetShortOrAny() const
531
0
            {
532
0
                if (!shortFlags.empty())
533
0
                {
534
0
                    return *shortFlags.begin();
535
0
                }
536
537
0
                if (!longFlags.empty())
538
0
                {
539
0
                    return *longFlags.begin();
540
0
                }
541
542
                // should be unreachable
543
0
                return ' ';
544
0
            }
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
0
    {
590
0
        return static_cast<Options>(static_cast<int>(lhs) | static_cast<int>(rhs));
591
0
    }
592
593
    inline Options operator & (Options lhs, Options rhs)
594
13.3k
    {
595
13.3k
        return static_cast<Options>(static_cast<int>(lhs) & static_cast<int>(rhs));
596
13.3k
    }
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
0
        {
769
0
#ifndef ARGS_NOEXCEPT
770
0
            if (max < min)
771
0
            {
772
0
                throw UsageError("Nargs: max > min");
773
0
            }
774
0
#endif
775
0
        }
776
777
6.68k
        Nargs(size_t num_) : min{num_}, max{num_}
778
6.68k
        {
779
6.68k
        }
780
781
        friend bool operator == (const Nargs &lhs, const Nargs &rhs)
782
0
        {
783
0
            return lhs.min == rhs.min && lhs.max == rhs.max;
784
0
        }
785
786
        friend bool operator != (const Nargs &lhs, const Nargs &rhs)
787
0
        {
788
0
            return !(lhs == rhs);
789
0
        }
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
3.62k
            Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {}
810
3.62k
            virtual ~Base() {}
811
812
            Options GetOptions() const noexcept
813
6.70k
            {
814
6.70k
                return options;
815
6.70k
            }
816
817
            bool IsRequired() const noexcept
818
19
            {
819
19
                return (GetOptions() & Options::Required) != Options::None;
820
19
            }
821
822
            virtual bool Matched() const noexcept
823
8.51k
            {
824
8.51k
                return matched;
825
8.51k
            }
826
827
            virtual void Validate(const std::string &, const std::string &) const
828
0
            {
829
0
            }
830
831
            operator bool() const noexcept
832
0
            {
833
0
                return Matched();
834
0
            }
835
836
            virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &, const unsigned indentLevel) const
837
0
            {
838
0
                std::tuple<std::string, std::string, unsigned> description;
839
0
                std::get<1>(description) = help;
840
0
                std::get<2>(description) = indentLevel;
841
0
                return { std::move(description) };
842
0
            }
843
844
            virtual std::vector<Command*> GetCommands()
845
2.71k
            {
846
2.71k
                return {};
847
2.71k
            }
848
849
            virtual bool IsGroup() const
850
39
            {
851
39
                return false;
852
39
            }
853
854
            virtual FlagBase *Match(const EitherFlag &)
855
0
            {
856
0
                return nullptr;
857
0
            }
858
859
            virtual PositionalBase *GetNextPositional()
860
546
            {
861
546
                return nullptr;
862
546
            }
863
864
            virtual std::vector<FlagBase*> GetAllFlags()
865
0
            {
866
0
                return {};
867
0
            }
868
869
            virtual bool HasFlag() const
870
0
            {
871
0
                return false;
872
0
            }
873
874
            virtual bool HasPositional() const
875
0
            {
876
0
                return false;
877
0
            }
878
879
            virtual bool HasCommand() const
880
39
            {
881
39
                return false;
882
39
            }
883
884
            virtual std::vector<std::string> GetProgramLine(const HelpParams &) const
885
0
            {
886
0
                return {};
887
0
            }
888
889
            /// Sets a kick-out value for building subparsers
890
            void KickOut(bool kickout_) noexcept
891
0
            {
892
0
                if (kickout_)
893
0
                {
894
0
                    options = options | Options::KickOut;
895
0
                }
896
0
                else
897
0
                {
898
0
                    options = static_cast<Options>(static_cast<int>(options) & ~static_cast<int>(Options::KickOut));
899
0
                }
900
0
            }
901
902
            /// Gets the kick-out value for building subparsers
903
            bool KickOut() const noexcept
904
6.65k
            {
905
6.65k
                return (options & Options::KickOut) != Options::None;
906
6.65k
            }
907
908
            virtual void Reset() noexcept
909
3.62k
            {
910
3.62k
                matched = false;
911
#ifdef ARGS_NOEXCEPT
912
                error = Error::None;
913
                errorMsg.clear();
914
#endif
915
3.62k
            }
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
            virtual 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
0
            virtual std::string GetDefaultString(const HelpParams&) const { return {}; }
945
946
0
            virtual std::vector<std::string> GetChoicesStrings(const HelpParams&) const { return {}; }
947
948
0
            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
0
            {
952
0
                if (isManual && !manual.empty())
953
0
                {
954
0
                    dest += str;
955
0
                    dest += manual;
956
0
                }
957
0
                else if (!isManual && isGenerated && !generated.empty())
958
0
                {
959
0
                    dest += str;
960
0
                    dest += generated;
961
0
                }
962
0
            }
963
964
        public:
965
2.71k
            NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {}
966
2.71k
            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
0
            {
973
0
                defaultStringManual = true;
974
0
                defaultString = str;
975
0
            }
976
977
            /** Gets default value string that will be added to argument description.
978
             */
979
            std::string HelpDefault(const HelpParams &params) const
980
0
            {
981
0
                return defaultStringManual ? defaultString : GetDefaultString(params);
982
0
            }
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
0
            {
989
0
                choicesStringManual = true;
990
0
                choicesStrings = array;
991
0
            }
992
993
            /** Gets choices strings that will be added to argument description.
994
             */
995
            std::vector<std::string> HelpChoices(const HelpParams &params) const
996
0
            {
997
0
                return choicesStringManual ? choicesStrings : GetChoicesStrings(params);
998
0
            }
999
1000
            virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned indentLevel) const override
1001
0
            {
1002
0
                std::tuple<std::string, std::string, unsigned> description;
1003
0
                std::get<0>(description) = GetNameString(params);
1004
0
                std::get<1>(description) = help;
1005
0
                std::get<2>(description) = indentLevel;
1006
1007
0
                AddDescriptionPostfix(std::get<1>(description), choicesStringManual, detail::Join(choicesStrings, ", "), params.addChoices, detail::Join(GetChoicesStrings(params), ", "), params.choiceString);
1008
0
                AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString);
1009
1010
0
                return { std::move(description) };
1011
0
            }
1012
1013
            virtual std::string Name() const
1014
21
            {
1015
21
                return name;
1016
21
            }
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
0
            {
1088
0
                const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name();
1089
0
                std::string flags;
1090
0
                const auto flagStrings = matcher.GetFlagStrings();
1091
0
                const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce;
1092
0
                for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it)
1093
0
                {
1094
0
                    auto &flag = *it;
1095
0
                    if (it != flagStrings.begin())
1096
0
                    {
1097
0
                        flags += ", ";
1098
0
                    }
1099
1100
0
                    flags += flag.isShort ? params.shortPrefix : params.longPrefix;
1101
0
                    flags += flag.str();
1102
1103
0
                    if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end()))
1104
0
                    {
1105
0
                        flags += flag.isShort ? params.shortSeparator : params.longSeparator;
1106
0
                        flags += params.valueOpen + postfix + params.valueClose;
1107
0
                    }
1108
0
                }
1109
1110
0
                return flags;
1111
0
            }
1112
1113
        public:
1114
0
            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
2.71k
            FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {}
1117
1118
2.71k
            virtual ~FlagBase() {}
1119
1120
            virtual FlagBase *Match(const EitherFlag &flag) override
1121
19.5k
            {
1122
19.5k
                if (matcher.Match(flag))
1123
6.68k
                {
1124
6.68k
                    if ((GetOptions() & Options::Single) != Options::None && matched)
1125
0
                    {
1126
0
                        std::ostringstream problem;
1127
0
                        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
0
                        throw ExtraError(problem.str());
1133
0
#endif
1134
0
                    }
1135
6.68k
                    matched = true;
1136
6.68k
                    return this;
1137
6.68k
                }
1138
12.8k
                return nullptr;
1139
19.5k
            }
1140
1141
            virtual std::vector<FlagBase*> GetAllFlags() override
1142
0
            {
1143
0
                return { this };
1144
0
            }
1145
1146
            const Matcher &GetMatcher() const
1147
0
            {
1148
0
                return matcher;
1149
0
            }
1150
1151
            virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1152
39
            {
1153
39
                if (!Matched() && IsRequired())
1154
0
                {
1155
0
                        std::ostringstream problem;
1156
0
                        problem << "Flag '" << matcher.GetLongOrAny().str(shortPrefix, longPrefix) << "' is required";
1157
#ifdef ARGS_NOEXCEPT
1158
                        error = Error::Required;
1159
                        errorMsg = problem.str();
1160
#else
1161
0
                        throw RequiredError(problem.str());
1162
0
#endif
1163
0
                }
1164
39
            }
1165
1166
            virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1167
0
            {
1168
0
                if (!params.proglineShowFlags)
1169
0
                {
1170
0
                    return {};
1171
0
                }
1172
1173
0
                const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name();
1174
0
                const EitherFlag flag = params.proglinePreferShortFlags ? matcher.GetShortOrAny() : matcher.GetLongOrAny();
1175
0
                std::string res = flag.str(params.shortPrefix, params.longPrefix);
1176
0
                if (!postfix.empty())
1177
0
                {
1178
0
                    res += params.proglineValueOpen + postfix + params.proglineValueClose;
1179
0
                }
1180
1181
0
                return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose
1182
0
                                      : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose };
1183
0
            }
1184
1185
            virtual bool HasFlag() const override
1186
0
            {
1187
0
                return true;
1188
0
            }
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
0
            ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : FlagBase(name_, help_, std::move(matcher_), extraError_) {}
1229
0
            ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : FlagBase(name_, help_, std::move(matcher_), options_) {}
1230
0
            virtual ~ValueFlagBase() {}
1231
1232
            virtual Nargs NumberOfArguments() const noexcept override
1233
0
            {
1234
0
                return 1;
1235
0
            }
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
0
            virtual ~CompletionFlag() {}
1252
1253
            virtual Nargs NumberOfArguments() const noexcept override
1254
0
            {
1255
0
                return 2;
1256
0
            }
1257
1258
            virtual void ParseValue(const std::vector<std::string> &value_) override
1259
0
            {
1260
0
                syntax = value_.at(0);
1261
0
                std::istringstream(value_.at(1)) >> cword;
1262
0
            }
1263
1264
            /** Get the completion reply
1265
             */
1266
            std::string Get() noexcept
1267
0
            {
1268
0
                return detail::Join(reply, "\n");
1269
0
            }
1270
1271
            virtual void Reset() noexcept override
1272
0
            {
1273
0
                ValueFlagBase::Reset();
1274
0
                cword = 0;
1275
0
                syntax.clear();
1276
0
                reply.clear();
1277
0
            }
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
0
            PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {}
1290
0
            virtual ~PositionalBase() {}
1291
1292
            bool Ready()
1293
0
            {
1294
0
                return ready;
1295
0
            }
1296
1297
            virtual void ParseValue(const std::string &value_) = 0;
1298
1299
            virtual void Reset() noexcept override
1300
0
            {
1301
0
                matched = false;
1302
0
                ready = true;
1303
0
#ifdef ARGS_NOEXCEPT
1304
0
                error = Error::None;
1305
0
                errorMsg.clear();
1306
0
#endif
1307
0
            }
1308
1309
            virtual PositionalBase *GetNextPositional() override
1310
0
            {
1311
0
                return Ready() ? this : nullptr;
1312
0
            }
1313
1314
            virtual bool HasPositional() const override
1315
0
            {
1316
0
                return true;
1317
0
            }
1318
1319
            virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1320
0
            {
1321
0
                return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose
1322
0
                                      : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose };
1323
0
            }
1324
1325
            virtual void Validate(const std::string &, const std::string &) const override
1326
0
            {
1327
0
                if (IsRequired() && !Matched())
1328
0
                {
1329
0
                    std::ostringstream problem;
1330
0
                    problem << "Option '" << Name() << "' is required";
1331
0
#ifdef ARGS_NOEXCEPT
1332
0
                    error = Error::Required;
1333
0
                    errorMsg = problem.str();
1334
0
#else
1335
0
                    throw RequiredError(problem.str());
1336
0
#endif
1337
0
                }
1338
0
            }
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
0
                {
1356
0
                    return group.MatchedChildren() == 1;
1357
0
                }
1358
1359
                static bool AtLeastOne(const Group &group)
1360
0
                {
1361
0
                    return group.MatchedChildren() >= 1;
1362
0
                }
1363
1364
                static bool AtMostOne(const Group &group)
1365
0
                {
1366
0
                    return group.MatchedChildren() <= 1;
1367
0
                }
1368
1369
                static bool All(const Group &group)
1370
0
                {
1371
0
                    return group.Children().size() == group.MatchedChildren();
1372
0
                }
1373
1374
                static bool AllOrNone(const Group &group)
1375
0
                {
1376
0
                    return (All(group) || None(group));
1377
0
                }
1378
1379
                static bool AllChildGroups(const Group &group)
1380
0
                {
1381
0
                    return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool {
1382
0
                            return child->IsGroup() && !child->Matched();
1383
0
                            });
1384
0
                }
1385
1386
                static bool DontCare(const Group &)
1387
0
                {
1388
0
                    return true;
1389
0
                }
1390
1391
                static bool CareTooMuch(const Group &)
1392
0
                {
1393
0
                    return false;
1394
0
                }
1395
1396
                static bool None(const Group &group)
1397
0
                {
1398
0
                    return group.MatchedChildren() == 0;
1399
0
                }
1400
            };
1401
            /// If help is empty, this group will not be printed in help output
1402
906
            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
0
            {
1406
0
                group_.Add(*this);
1407
0
            }
1408
906
            virtual ~Group() {}
1409
1410
            /** Append a child to this Group.
1411
             */
1412
            void Add(Base &child)
1413
2.71k
            {
1414
2.71k
                children.emplace_back(&child);
1415
2.71k
            }
1416
1417
            /** Get all this group's children
1418
             */
1419
            const std::vector<Base *> &Children() const
1420
9.40k
            {
1421
9.40k
                return children;
1422
9.40k
            }
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
7.37k
            {
1431
7.37k
                for (Base *child: Children())
1432
19.5k
                {
1433
19.5k
                    if (FlagBase *match = child->Match(flag))
1434
6.68k
                    {
1435
6.68k
                        return match;
1436
6.68k
                    }
1437
19.5k
                }
1438
681
                return nullptr;
1439
7.37k
            }
1440
1441
            virtual std::vector<FlagBase*> GetAllFlags() override
1442
0
            {
1443
0
                std::vector<FlagBase*> res;
1444
0
                for (Base *child: Children())
1445
0
                {
1446
0
                    auto childRes = child->GetAllFlags();
1447
0
                    res.insert(res.end(), childRes.begin(), childRes.end());
1448
0
                }
1449
0
                return res;
1450
0
            }
1451
1452
            virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
1453
0
            {
1454
0
                for (Base *child: Children())
1455
0
                {
1456
0
                    child->Validate(shortPrefix, longPrefix);
1457
0
                }
1458
0
            }
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
182
            {
1466
182
                for (Base *child: Children())
1467
546
                {
1468
546
                    if (auto next = child->GetNextPositional())
1469
0
                    {
1470
0
                        return next;
1471
0
                    }
1472
546
                }
1473
182
                return nullptr;
1474
182
            }
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
0
            {
1482
0
                return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); });
1483
0
            }
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
0
            {
1491
0
                return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); });
1492
0
            }
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
13
            {
1500
39
                return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); });
1501
13
            }
1502
1503
            /** Count the number of matched children this group has
1504
             */
1505
            std::vector<Base *>::size_type MatchedChildren() const
1506
0
            {
1507
0
                // Cast to avoid warnings from -Wsign-conversion
1508
0
                return static_cast<std::vector<Base *>::size_type>(
1509
0
                        std::count_if(std::begin(Children()), std::end(Children()), [](const Base *child){return child->Matched();}));
1510
0
            }
1511
1512
            /** Whether or not this group matches validation
1513
             */
1514
            virtual bool Matched() const noexcept override
1515
0
            {
1516
0
                return validator(*this);
1517
0
            }
1518
1519
            /** Get validation
1520
             */
1521
            bool Get() const
1522
0
            {
1523
0
                return Matched();
1524
0
            }
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
0
            {
1530
0
                std::vector<std::tuple<std::string, std::string, unsigned int>> descriptions;
1531
1532
                // Push that group description on the back if not empty
1533
0
                unsigned addindent = 0;
1534
0
                if (!help.empty())
1535
0
                {
1536
0
                    descriptions.emplace_back(help, "", indent);
1537
0
                    addindent = 1;
1538
0
                }
1539
1540
0
                for (Base *child: Children())
1541
0
                {
1542
0
                    if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
1543
0
                    {
1544
0
                        continue;
1545
0
                    }
1546
1547
0
                    auto groupDescriptions = child->GetDescription(params, indent + addindent);
1548
0
                    descriptions.insert(
1549
0
                        std::end(descriptions),
1550
0
                        std::make_move_iterator(std::begin(groupDescriptions)),
1551
0
                        std::make_move_iterator(std::end(groupDescriptions)));
1552
0
                }
1553
0
                return descriptions;
1554
0
            }
1555
1556
            /** Get the names of positional parameters
1557
             */
1558
            virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
1559
0
            {
1560
0
                std::vector <std::string> names;
1561
0
                for (Base *child: Children())
1562
0
                {
1563
0
                    if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None)
1564
0
                    {
1565
0
                        continue;
1566
0
                    }
1567
1568
0
                    auto groupNames = child->GetProgramLine(params);
1569
0
                    names.insert(
1570
0
                        std::end(names),
1571
0
                        std::make_move_iterator(std::begin(groupNames)),
1572
0
                        std::make_move_iterator(std::end(groupNames)));
1573
0
                }
1574
0
                return names;
1575
0
            }
1576
1577
            virtual std::vector<Command*> GetCommands() override
1578
906
            {
1579
906
                std::vector<Command*> res;
1580
906
                for (const auto &child : Children())
1581
2.71k
                {
1582
2.71k
                    auto subparsers = child->GetCommands();
1583
2.71k
                    res.insert(std::end(res), std::begin(subparsers), std::end(subparsers));
1584
2.71k
                }
1585
906
                return res;
1586
906
            }
1587
1588
            virtual bool IsGroup() const override
1589
0
            {
1590
0
                return true;
1591
0
            }
1592
1593
            virtual void Reset() noexcept override
1594
906
            {
1595
906
                Base::Reset();
1596
1597
906
                for (auto &child: Children())
1598
2.71k
                {
1599
2.71k
                    child->Reset();
1600
2.71k
                }
1601
#ifdef ARGS_NOEXCEPT
1602
                error = Error::None;
1603
                errorMsg.clear();
1604
#endif
1605
906
            }
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
1626
            /// Only for ARGS_NOEXCEPT
1627
            virtual std::string GetErrorMsg() const override
1628
            {
1629
                if (error != Error::None)
1630
                {
1631
                    return errorMsg;
1632
                }
1633
1634
                auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;});
1635
                if (it == Children().end())
1636
                {
1637
                    return "";
1638
                } else
1639
                {
1640
                    return (*it)->GetErrorMsg();
1641
                }
1642
            }
1643
#endif
1644
1645
    };
1646
1647
    /** Class for using global options in ArgumentParser.
1648
     */
1649
    class GlobalOptions : public Group
1650
    {
1651
        public:
1652
            GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global)
1653
0
            {
1654
0
                Add(options_);
1655
0
            }
1656
    };
1657
1658
    /** Utility class for building subparsers with coroutines/callbacks.
1659
     *
1660
     * Brief example:
1661
     * \code
1662
     * Command command(argumentParser, "command", "my command", [](args::Subparser &s)
1663
     * {
1664
     *      // your command flags/positionals
1665
     *      s.Parse(); //required
1666
     *      //your command code
1667
     * });
1668
     * \endcode
1669
     *
1670
     * For ARGS_NOEXCEPT mode don't forget to check `s.GetError()` after `s.Parse()`
1671
     * and return if it isn't equals to args::Error::None.
1672
     *
1673
     * \sa Command
1674
     */
1675
    class Subparser : public Group
1676
    {
1677
        private:
1678
            std::vector<std::string> args;
1679
            std::vector<std::string> kicked;
1680
            ArgumentParser *parser = nullptr;
1681
            const HelpParams &helpParams;
1682
            const Command &command;
1683
            bool isParsed = false;
1684
1685
        public:
1686
            Subparser(std::vector<std::string> args_, ArgumentParser &parser_, const Command &command_, const HelpParams &helpParams_)
1687
0
                : Group({}, Validators::AllChildGroups), args(std::move(args_)), parser(&parser_), helpParams(helpParams_), command(command_)
1688
0
            {
1689
0
            }
1690
1691
0
            Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_)
1692
0
            {
1693
0
            }
1694
1695
            Subparser(const Subparser&) = delete;
1696
            Subparser(Subparser&&) = delete;
1697
            Subparser &operator = (const Subparser&) = delete;
1698
            Subparser &operator = (Subparser&&) = delete;
1699
1700
            const Command &GetCommand()
1701
0
            {
1702
0
                return command;
1703
0
            }
1704
1705
            /** (INTERNAL) Determines whether Parse was called or not.
1706
             */
1707
            bool IsParsed() const
1708
0
            {
1709
0
                return isParsed;
1710
0
            }
1711
1712
            /** Continue parsing arguments for new command.
1713
             */
1714
            void Parse();
1715
1716
            /** Returns a vector of kicked out arguments.
1717
             *
1718
             * \sa Base::KickOut
1719
             */
1720
            const std::vector<std::string> &KickedOut() const noexcept
1721
0
            {
1722
0
                return kicked;
1723
0
            }
1724
    };
1725
1726
    /** Main class for building subparsers.
1727
     *
1728
     * /sa Subparser
1729
     */
1730
    class Command : public Group
1731
    {
1732
        private:
1733
            friend class Subparser;
1734
1735
            std::string name;
1736
            std::string help;
1737
            std::string description;
1738
            std::string epilog;
1739
            std::string proglinePostfix;
1740
1741
            std::function<void(Subparser&)> parserCoroutine;
1742
            bool commandIsRequired = true;
1743
            Command *selectedCommand = nullptr;
1744
1745
            mutable std::vector<std::tuple<std::string, std::string, unsigned>> subparserDescription;
1746
            mutable std::vector<std::string> subparserProgramLine;
1747
            mutable bool subparserHasFlag = false;
1748
            mutable bool subparserHasPositional = false;
1749
            mutable bool subparserHasCommand = false;
1750
#ifdef ARGS_NOEXCEPT
1751
            mutable Error subparserError = Error::None;
1752
#endif
1753
            mutable Subparser *subparser = nullptr;
1754
1755
        protected:
1756
1757
            class RaiiSubparser
1758
            {
1759
                public:
1760
                    RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_);
1761
                    RaiiSubparser(const Command &command_, const HelpParams &params_);
1762
1763
                    ~RaiiSubparser()
1764
0
                    {
1765
0
                        command.subparser = oldSubparser;
1766
0
                    }
1767
1768
                    Subparser &Parser()
1769
0
                    {
1770
0
                        return parser;
1771
0
                    }
1772
1773
                private:
1774
                    const Command &command;
1775
                    Subparser parser;
1776
                    Subparser *oldSubparser;
1777
            };
1778
1779
906
            Command() = default;
1780
1781
            std::function<void(Subparser&)> &GetCoroutine()
1782
0
            {
1783
0
                return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine;
1784
0
            }
1785
1786
            Command &SelectedCommand()
1787
0
            {
1788
0
                Command *res = this;
1789
0
                while (res->selectedCommand != nullptr)
1790
0
                {
1791
0
                    res = res->selectedCommand;
1792
0
                }
1793
1794
0
                return *res;
1795
0
            }
1796
1797
            const Command &SelectedCommand() const
1798
0
            {
1799
0
                const Command *res = this;
1800
0
                while (res->selectedCommand != nullptr)
1801
0
                {
1802
0
                    res = res->selectedCommand;
1803
0
                }
1804
0
1805
0
                return *res;
1806
0
            }
1807
1808
            void UpdateSubparserHelp(const HelpParams &params) const
1809
0
            {
1810
0
                if (parserCoroutine)
1811
0
                {
1812
0
                    RaiiSubparser coro(*this, params);
1813
0
#ifndef ARGS_NOEXCEPT
1814
0
                    try
1815
0
                    {
1816
0
                        parserCoroutine(coro.Parser());
1817
0
                    }
1818
0
                    catch (args::SubparserError&)
1819
0
                    {
1820
0
                    }
1821
#else
1822
                    parserCoroutine(coro.Parser());
1823
#endif
1824
0
                }
1825
0
            }
1826
1827
        public:
1828
            Command(Group &base_, std::string name_, std::string help_, std::function<void(Subparser&)> coroutine_ = {})
1829
                : name(std::move(name_)), help(std::move(help_)), parserCoroutine(std::move(coroutine_))
1830
0
            {
1831
0
                base_.Add(*this);
1832
0
            }
1833
1834
            /** The description that appears on the prog line after options
1835
             */
1836
            const std::string &ProglinePostfix() const
1837
0
            { return proglinePostfix; }
1838
1839
            /** The description that appears on the prog line after options
1840
             */
1841
            void ProglinePostfix(const std::string &proglinePostfix_)
1842
0
            { this->proglinePostfix = proglinePostfix_; }
1843
1844
            /** The description that appears above options
1845
             */
1846
            const std::string &Description() const
1847
0
            { return description; }
1848
            /** The description that appears above options
1849
             */
1850
1851
            void Description(const std::string &description_)
1852
906
            { this->description = description_; }
1853
1854
            /** The description that appears below options
1855
             */
1856
            const std::string &Epilog() const
1857
0
            { return epilog; }
1858
1859
            /** The description that appears below options
1860
             */
1861
            void Epilog(const std::string &epilog_)
1862
906
            { this->epilog = epilog_; }
1863
1864
            /** The name of command
1865
             */
1866
            const std::string &Name() const
1867
0
            { return name; }
1868
1869
            /** The description of command
1870
             */
1871
            const std::string &Help() const
1872
0
            { return help; }
1873
1874
            /** If value is true, parser will fail if no command was parsed.
1875
             *
1876
             * Default: true.
1877
             */
1878
            void RequireCommand(bool value)
1879
0
            { commandIsRequired = value; }
1880
1881
            virtual bool IsGroup() const override
1882
0
            { return false; }
1883
1884
            virtual bool Matched() const noexcept override
1885
8.47k
            { return Base::Matched(); }
1886
1887
            operator bool() const noexcept
1888
0
            { return Matched(); }
1889
1890
            void Match() noexcept
1891
0
            { matched = true; }
1892
1893
            void SelectCommand(Command *c) noexcept
1894
0
            {
1895
0
                selectedCommand = c;
1896
1897
0
                if (c != nullptr)
1898
0
                {
1899
0
                    c->Match();
1900
0
                }
1901
0
            }
1902
1903
            virtual FlagBase *Match(const EitherFlag &flag) override
1904
7.37k
            {
1905
7.37k
                if (selectedCommand != nullptr)
1906
0
                {
1907
0
                    if (auto *res = selectedCommand->Match(flag))
1908
0
                    {
1909
0
                        return res;
1910
0
                    }
1911
1912
0
                    for (auto *child: Children())
1913
0
                    {
1914
0
                        if ((child->GetOptions() & Options::Global) != Options::None)
1915
0
                        {
1916
0
                            if (auto *res = child->Match(flag))
1917
0
                            {
1918
0
                                return res;
1919
0
                            }
1920
0
                        }
1921
0
                    }
1922
1923
0
                    return nullptr;
1924
0
                }
1925
1926
7.37k
                if (subparser != nullptr)
1927
0
                {
1928
0
                    return subparser->Match(flag);
1929
0
                }
1930
1931
7.37k
                return Matched() ? Group::Match(flag) : nullptr;
1932
7.37k
            }
1933
1934
            virtual std::vector<FlagBase*> GetAllFlags() override
1935
0
            {
1936
0
                std::vector<FlagBase*> res;
1937
1938
0
                if (!Matched())
1939
0
                {
1940
0
                    return res;
1941
0
                }
1942
1943
0
                for (auto *child: Children())
1944
0
                {
1945
0
                    if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None)
1946
0
                    {
1947
0
                        auto childFlags = child->GetAllFlags();
1948
0
                        res.insert(res.end(), childFlags.begin(), childFlags.end());
1949
0
                    }
1950
0
                }
1951
1952
0
                if (selectedCommand != nullptr)
1953
0
                {
1954
0
                    auto childFlags = selectedCommand->GetAllFlags();
1955
0
                    res.insert(res.end(), childFlags.begin(), childFlags.end());
1956
0
                }
1957
1958
0
                if (subparser != nullptr)
1959
0
                {
1960
0
                    auto childFlags = subparser->GetAllFlags();
1961
0
                    res.insert(res.end(), childFlags.begin(), childFlags.end());
1962
0
                }
1963
1964
0
                return res;
1965
0
            }
1966
1967
            virtual PositionalBase *GetNextPositional() override
1968
182
            {
1969
182
                if (selectedCommand != nullptr)
1970
0
                {
1971
0
                    if (auto *res = selectedCommand->GetNextPositional())
1972
0
                    {
1973
0
                        return res;
1974
0
                    }
1975
1976
0
                    for (auto *child: Children())
1977
0
                    {
1978
0
                        if ((child->GetOptions() & Options::Global) != Options::None)
1979
0
                        {
1980
0
                            if (auto *res = child->GetNextPositional())
1981
0
                            {
1982
0
                                return res;
1983
0
                            }
1984
0
                        }
1985
0
                    }
1986
1987
0
                    return nullptr;
1988
0
                }
1989
1990
182
                if (subparser != nullptr)
1991
0
                {
1992
0
                    return subparser->GetNextPositional();
1993
0
                }
1994
1995
182
                return Matched() ? Group::GetNextPositional() : nullptr;
1996
182
            }
1997
1998
            virtual bool HasFlag() const override
1999
0
            {
2000
0
                return subparserHasFlag || Group::HasFlag();
2001
0
            }
2002
2003
            virtual bool HasPositional() const override
2004
0
            {
2005
0
                return subparserHasPositional || Group::HasPositional();
2006
0
            }
2007
2008
            virtual bool HasCommand() const override
2009
0
            {
2010
0
                return true;
2011
0
            }
2012
2013
            std::vector<std::string> GetCommandProgramLine(const HelpParams &params) const
2014
0
            {
2015
0
                UpdateSubparserHelp(params);
2016
2017
0
                std::vector<std::string> res;
2018
2019
0
                if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags)
2020
0
                {
2021
0
                    res.push_back(params.proglineOptions);
2022
0
                }
2023
2024
0
                auto group_res = Group::GetProgramLine(params);
2025
0
                std::move(std::move(group_res).begin(), std::move(group_res).end(), std::back_inserter(res));
2026
2027
0
                res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end());
2028
2029
0
                if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand))
2030
0
                {
2031
0
                    res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]");
2032
0
                }
2033
2034
0
                if (!Name().empty())
2035
0
                {
2036
0
                    res.insert(res.begin(), Name());
2037
0
                }
2038
2039
0
                if (!ProglinePostfix().empty())
2040
0
                {
2041
0
                    std::string line;
2042
0
                    for (auto c : ProglinePostfix())
2043
0
                    {
2044
0
                        if (std::isspace(static_cast<unsigned char>(c)))
2045
0
                        {
2046
0
                            if (!line.empty())
2047
0
                            {
2048
0
                                res.push_back(line);
2049
0
                                line.clear();
2050
0
                            }
2051
2052
0
                            if (c == '\n')
2053
0
                            {
2054
0
                                res.push_back("\n");
2055
0
                            }
2056
0
                        }
2057
0
                        else
2058
0
                        {
2059
0
                            line += c;
2060
0
                        }
2061
0
                    }
2062
2063
0
                    if (!line.empty())
2064
0
                    {
2065
0
                        res.push_back(line);
2066
0
                    }
2067
0
                }
2068
2069
0
                return res;
2070
0
            }
2071
2072
            virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
2073
0
            {
2074
0
                if (!Matched())
2075
0
                {
2076
0
                    return {};
2077
0
                }
2078
2079
0
                return GetCommandProgramLine(params);
2080
0
            }
2081
2082
            virtual std::vector<Command*> GetCommands() override
2083
906
            {
2084
906
                if (selectedCommand != nullptr)
2085
0
                {
2086
0
                    return selectedCommand->GetCommands();
2087
0
                }
2088
2089
906
                if (Matched())
2090
906
                {
2091
906
                    return Group::GetCommands();
2092
906
                }
2093
2094
0
                return { this };
2095
906
            }
2096
2097
            virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
2098
0
            {
2099
0
                std::vector<std::tuple<std::string, std::string, unsigned>> descriptions;
2100
0
                unsigned addindent = 0;
2101
2102
0
                UpdateSubparserHelp(params);
2103
2104
0
                if (!Matched())
2105
0
                {
2106
0
                    if (params.showCommandFullHelp)
2107
0
                    {
2108
0
                        std::ostringstream s;
2109
0
                        bool empty = true;
2110
0
                        for (const auto &progline: GetCommandProgramLine(params))
2111
0
                        {
2112
0
                            if (!empty)
2113
0
                            {
2114
0
                                s << ' ';
2115
0
                            }
2116
0
                            else
2117
0
                            {
2118
0
                                empty = false;
2119
0
                            }
2120
2121
0
                            s << progline;
2122
0
                        }
2123
2124
0
                        descriptions.emplace_back(s.str(), "", indent);
2125
0
                    }
2126
0
                    else
2127
0
                    {
2128
0
                        descriptions.emplace_back(Name(), help, indent);
2129
0
                    }
2130
2131
0
                    if (!params.showCommandChildren && !params.showCommandFullHelp)
2132
0
                    {
2133
0
                        return descriptions;
2134
0
                    }
2135
2136
0
                    addindent = 1;
2137
0
                }
2138
2139
0
                if (params.showCommandFullHelp && !Matched())
2140
0
                {
2141
0
                    descriptions.emplace_back("", "", indent + addindent);
2142
0
                    descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent);
2143
0
                    descriptions.emplace_back("", "", indent + addindent);
2144
0
                }
2145
2146
0
                for (Base *child: Children())
2147
0
                {
2148
0
                    if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
2149
0
                    {
2150
0
                        continue;
2151
0
                    }
2152
2153
0
                    auto groupDescriptions = child->GetDescription(params, indent + addindent);
2154
0
                    descriptions.insert(
2155
0
                                        std::end(descriptions),
2156
0
                                        std::make_move_iterator(std::begin(groupDescriptions)),
2157
0
                                        std::make_move_iterator(std::end(groupDescriptions)));
2158
0
                }
2159
2160
0
                for (auto childDescription: subparserDescription)
2161
0
                {
2162
0
                    std::get<2>(childDescription) += indent + addindent;
2163
0
                    descriptions.push_back(std::move(childDescription));
2164
0
                }
2165
2166
0
                if (params.showCommandFullHelp && !Matched())
2167
0
                {
2168
0
                    descriptions.emplace_back("", "", indent + addindent);
2169
0
                    if (!Epilog().empty())
2170
0
                    {
2171
0
                        descriptions.emplace_back(Epilog(), "", indent + addindent);
2172
0
                        descriptions.emplace_back("", "", indent + addindent);
2173
0
                    }
2174
0
                }
2175
2176
0
                return descriptions;
2177
0
            }
2178
2179
            virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override
2180
13
            {
2181
13
                if (!Matched())
2182
0
                {
2183
0
                    return;
2184
0
                }
2185
2186
13
                auto onValidationError = [&]
2187
13
                {
2188
0
                    std::ostringstream problem;
2189
0
                    problem << "Group validation failed somewhere!";
2190
#ifdef ARGS_NOEXCEPT
2191
                    error = Error::Validation;
2192
                    errorMsg = problem.str();
2193
#else
2194
0
                    throw ValidationError(problem.str());
2195
0
#endif
2196
0
                };
2197
2198
13
                for (Base *child: Children())
2199
39
                {
2200
39
                    if (child->IsGroup() && !child->Matched())
2201
0
                    {
2202
0
                        onValidationError();
2203
0
                    }
2204
2205
39
                    child->Validate(shortprefix, longprefix);
2206
39
                }
2207
2208
13
                if (subparser != nullptr)
2209
0
                {
2210
0
                    subparser->Validate(shortprefix, longprefix);
2211
0
                    if (!subparser->Matched())
2212
0
                    {
2213
0
                        onValidationError();
2214
0
                    }
2215
0
                }
2216
2217
13
                if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand))
2218
0
                {
2219
0
                    std::ostringstream problem;
2220
0
                    problem << "Command is required";
2221
#ifdef ARGS_NOEXCEPT
2222
                    error = Error::Validation;
2223
                    errorMsg = problem.str();
2224
#else
2225
0
                    throw ValidationError(problem.str());
2226
0
#endif
2227
0
                }
2228
13
            }
2229
2230
            virtual void Reset() noexcept override
2231
906
            {
2232
906
                Group::Reset();
2233
906
                selectedCommand = nullptr;
2234
906
                subparserProgramLine.clear();
2235
906
                subparserDescription.clear();
2236
906
                subparserHasFlag = false;
2237
906
                subparserHasPositional = false;
2238
906
                subparserHasCommand = false;
2239
#ifdef ARGS_NOEXCEPT
2240
                subparserError = Error::None;
2241
#endif
2242
906
            }
2243
2244
#ifdef ARGS_NOEXCEPT
2245
            /// Only for ARGS_NOEXCEPT
2246
            virtual Error GetError() const override
2247
            {
2248
                if (!Matched())
2249
                {
2250
                    return Error::None;
2251
                }
2252
2253
                if (error != Error::None)
2254
                {
2255
                    return error;
2256
                }
2257
2258
                if (subparserError != Error::None)
2259
                {
2260
                    return subparserError;
2261
                }
2262
2263
                return Group::GetError();
2264
            }
2265
#endif
2266
    };
2267
2268
    /** The main user facing command line argument parser class
2269
     */
2270
    class ArgumentParser : public Command
2271
    {
2272
        friend class Subparser;
2273
2274
        private:
2275
            std::string longprefix;
2276
            std::string shortprefix;
2277
2278
            std::string longseparator;
2279
2280
            std::string terminator;
2281
2282
            bool allowJoinedShortValue = true;
2283
            bool allowJoinedLongValue = true;
2284
            bool allowSeparateShortValue = true;
2285
            bool allowSeparateLongValue = true;
2286
2287
            CompletionFlag *completion = nullptr;
2288
            bool readCompletion = false;
2289
2290
        protected:
2291
            enum class OptionType
2292
            {
2293
                LongFlag,
2294
                ShortFlag,
2295
                Positional
2296
            };
2297
2298
            OptionType ParseOption(const std::string &s, bool allowEmpty = false)
2299
1.81k
            {
2300
1.81k
                if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length()))
2301
538
                {
2302
538
                    return OptionType::LongFlag;
2303
538
                }
2304
2305
1.27k
                if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length()))
2306
916
                {
2307
916
                    return OptionType::ShortFlag;
2308
916
                }
2309
2310
362
                return OptionType::Positional;
2311
1.27k
            }
2312
2313
            template <typename It>
2314
            bool Complete(FlagBase &flag, It it, It end)
2315
0
            {
2316
0
                auto nextIt = it;
2317
0
                if (!readCompletion || (++nextIt != end))
2318
0
                {
2319
0
                    return false;
2320
0
                }
2321
2322
0
                const auto &chunk = *it;
2323
0
                for (auto &choice : flag.HelpChoices(helpParams))
2324
0
                {
2325
0
                    AddCompletionReply(chunk, choice);
2326
0
                }
2327
2328
0
#ifndef ARGS_NOEXCEPT
2329
0
                throw Completion(completion->Get());
2330
#else
2331
                return true;
2332
#endif
2333
0
            }
Unexecuted instantiation: bool args::ArgumentParser::Complete<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(args::FlagBase&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>)
Unexecuted instantiation: bool args::ArgumentParser::Complete<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(args::FlagBase&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>)
2334
2335
            /** (INTERNAL) Parse flag's values
2336
             *
2337
             * \param arg The string to display in error message as a flag name
2338
             * \param[in, out] it The iterator to first value. It will point to the last value
2339
             * \param end The end iterator
2340
             * \param joinedArg Joined value (e.g. bar in --foo=bar)
2341
             * \param canDiscardJoined If true joined value can be parsed as flag not as a value (as in -abcd)
2342
             * \param[out] values The vector to store parsed arg's values
2343
             */
2344
            template <typename It>
2345
            std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end,
2346
                                        const bool allowSeparate, const bool allowJoined,
2347
                                        const bool hasJoined, const std::string &joinedArg,
2348
                                        const bool canDiscardJoined, std::vector<std::string> &values)
2349
6.68k
            {
2350
6.68k
                values.clear();
2351
2352
6.68k
                Nargs nargs = flag.NumberOfArguments();
2353
2354
6.68k
                if (hasJoined && !allowJoined && nargs.min != 0)
2355
0
                {
2356
0
                    return "Flag '" + arg + "' was passed a joined argument, but these are disallowed";
2357
0
                }
2358
2359
6.68k
                if (hasJoined)
2360
6.40k
                {
2361
6.40k
                    if (!canDiscardJoined || nargs.max != 0)
2362
9
                    {
2363
9
                        values.push_back(joinedArg);
2364
9
                    }
2365
6.40k
                } else if (!allowSeparate)
2366
0
                {
2367
0
                    if (nargs.min != 0)
2368
0
                    {
2369
0
                        return "Flag '" + arg + "' was passed a separate argument, but these are disallowed";
2370
0
                    }
2371
0
                } else
2372
287
                {
2373
287
                    auto valueIt = it;
2374
287
                    ++valueIt;
2375
2376
287
                    while (valueIt != end &&
2377
287
                           values.size() < nargs.max &&
2378
287
                           (values.size() < nargs.min || ParseOption(*valueIt) == OptionType::Positional))
2379
0
                    {
2380
0
                        if (Complete(flag, valueIt, end))
2381
0
                        {
2382
0
                            it = end;
2383
0
                            return "";
2384
0
                        }
2385
2386
0
                        values.push_back(*valueIt);
2387
0
                        ++it;
2388
0
                        ++valueIt;
2389
0
                    }
2390
287
                }
2391
2392
6.68k
                if (values.size() > nargs.max)
2393
9
                {
2394
9
                    return "Passed an argument into a non-argument flag: " + arg;
2395
6.68k
                } else if (values.size() < nargs.min)
2396
0
                {
2397
0
                    if (nargs.min == 1 && nargs.max == 1)
2398
0
                    {
2399
0
                        return "Flag '" + arg + "' requires an argument but received none";
2400
0
                    } else if (nargs.min == 1)
2401
0
                    {
2402
0
                        return "Flag '" + arg + "' requires at least one argument but received none";
2403
0
                    } else if (nargs.min != nargs.max)
2404
0
                    {
2405
0
                        return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) +
2406
0
                               " arguments but received " + std::to_string(values.size());
2407
0
                    } else
2408
0
                    {
2409
0
                        return "Flag '" + arg + "' requires " + std::to_string(nargs.min) +
2410
0
                               " arguments but received " + std::to_string(values.size());
2411
0
                    }
2412
0
                }
2413
2414
6.68k
                return {};
2415
6.68k
            }
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > args::ArgumentParser::ParseArgsValues<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(args::FlagBase&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, bool, bool, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&)
Line
Count
Source
2349
6.68k
            {
2350
6.68k
                values.clear();
2351
2352
6.68k
                Nargs nargs = flag.NumberOfArguments();
2353
2354
6.68k
                if (hasJoined && !allowJoined && nargs.min != 0)
2355
0
                {
2356
0
                    return "Flag '" + arg + "' was passed a joined argument, but these are disallowed";
2357
0
                }
2358
2359
6.68k
                if (hasJoined)
2360
6.40k
                {
2361
6.40k
                    if (!canDiscardJoined || nargs.max != 0)
2362
9
                    {
2363
9
                        values.push_back(joinedArg);
2364
9
                    }
2365
6.40k
                } else if (!allowSeparate)
2366
0
                {
2367
0
                    if (nargs.min != 0)
2368
0
                    {
2369
0
                        return "Flag '" + arg + "' was passed a separate argument, but these are disallowed";
2370
0
                    }
2371
0
                } else
2372
287
                {
2373
287
                    auto valueIt = it;
2374
287
                    ++valueIt;
2375
2376
287
                    while (valueIt != end &&
2377
287
                           values.size() < nargs.max &&
2378
287
                           (values.size() < nargs.min || ParseOption(*valueIt) == OptionType::Positional))
2379
0
                    {
2380
0
                        if (Complete(flag, valueIt, end))
2381
0
                        {
2382
0
                            it = end;
2383
0
                            return "";
2384
0
                        }
2385
2386
0
                        values.push_back(*valueIt);
2387
0
                        ++it;
2388
0
                        ++valueIt;
2389
0
                    }
2390
287
                }
2391
2392
6.68k
                if (values.size() > nargs.max)
2393
9
                {
2394
9
                    return "Passed an argument into a non-argument flag: " + arg;
2395
6.68k
                } else if (values.size() < nargs.min)
2396
0
                {
2397
0
                    if (nargs.min == 1 && nargs.max == 1)
2398
0
                    {
2399
0
                        return "Flag '" + arg + "' requires an argument but received none";
2400
0
                    } else if (nargs.min == 1)
2401
0
                    {
2402
0
                        return "Flag '" + arg + "' requires at least one argument but received none";
2403
0
                    } else if (nargs.min != nargs.max)
2404
0
                    {
2405
0
                        return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) +
2406
0
                               " arguments but received " + std::to_string(values.size());
2407
0
                    } else
2408
0
                    {
2409
0
                        return "Flag '" + arg + "' requires " + std::to_string(nargs.min) +
2410
0
                               " arguments but received " + std::to_string(values.size());
2411
0
                    }
2412
0
                }
2413
2414
6.68k
                return {};
2415
6.68k
            }
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > args::ArgumentParser::ParseArgsValues<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(args::FlagBase&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>, bool, bool, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&)
2416
2417
            template <typename It>
2418
            bool ParseLong(It &it, It end)
2419
538
            {
2420
538
                const auto &chunk = *it;
2421
538
                const auto argchunk = chunk.substr(longprefix.size());
2422
                // Try to separate it, in case of a separator:
2423
538
                const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator);
2424
                // If the separator is in the argument, separate it.
2425
538
                const auto arg = (separator != argchunk.npos ?
2426
222
                    std::string(argchunk, 0, separator)
2427
538
                    : argchunk);
2428
538
                const auto joined = (separator != argchunk.npos ?
2429
222
                    argchunk.substr(separator + longseparator.size())
2430
538
                    : std::string());
2431
2432
538
                if (auto flag = Match(arg))
2433
85
                {
2434
85
                    std::vector<std::string> values;
2435
85
                    const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue,
2436
85
                                                                     separator != argchunk.npos, joined, false, values);
2437
85
                    if (!errorMessage.empty())
2438
9
                    {
2439
9
#ifndef ARGS_NOEXCEPT
2440
9
                        throw ParseError(errorMessage);
2441
#else
2442
                        error = Error::Parse;
2443
                        errorMsg = errorMessage;
2444
                        return false;
2445
#endif
2446
9
                    }
2447
2448
76
                    if (!readCompletion)
2449
76
                    {
2450
76
                        flag->ParseValue(values);
2451
76
                    }
2452
2453
76
                    if (flag->KickOut())
2454
0
                    {
2455
0
                        ++it;
2456
0
                        return false;
2457
0
                    }
2458
76
                } else
2459
453
                {
2460
453
                    const std::string errorMessage("Flag could not be matched: " + arg);
2461
453
#ifndef ARGS_NOEXCEPT
2462
453
                    throw ParseError(errorMessage);
2463
#else
2464
                    error = Error::Parse;
2465
                    errorMsg = errorMessage;
2466
                    return false;
2467
#endif
2468
453
                }
2469
2470
76
                return true;
2471
538
            }
bool args::ArgumentParser::ParseLong<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>)
Line
Count
Source
2419
538
            {
2420
538
                const auto &chunk = *it;
2421
538
                const auto argchunk = chunk.substr(longprefix.size());
2422
                // Try to separate it, in case of a separator:
2423
538
                const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator);
2424
                // If the separator is in the argument, separate it.
2425
538
                const auto arg = (separator != argchunk.npos ?
2426
222
                    std::string(argchunk, 0, separator)
2427
538
                    : argchunk);
2428
538
                const auto joined = (separator != argchunk.npos ?
2429
222
                    argchunk.substr(separator + longseparator.size())
2430
538
                    : std::string());
2431
2432
538
                if (auto flag = Match(arg))
2433
85
                {
2434
85
                    std::vector<std::string> values;
2435
85
                    const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue,
2436
85
                                                                     separator != argchunk.npos, joined, false, values);
2437
85
                    if (!errorMessage.empty())
2438
9
                    {
2439
9
#ifndef ARGS_NOEXCEPT
2440
9
                        throw ParseError(errorMessage);
2441
#else
2442
                        error = Error::Parse;
2443
                        errorMsg = errorMessage;
2444
                        return false;
2445
#endif
2446
9
                    }
2447
2448
76
                    if (!readCompletion)
2449
76
                    {
2450
76
                        flag->ParseValue(values);
2451
76
                    }
2452
2453
76
                    if (flag->KickOut())
2454
0
                    {
2455
0
                        ++it;
2456
0
                        return false;
2457
0
                    }
2458
76
                } else
2459
453
                {
2460
453
                    const std::string errorMessage("Flag could not be matched: " + arg);
2461
453
#ifndef ARGS_NOEXCEPT
2462
453
                    throw ParseError(errorMessage);
2463
#else
2464
                    error = Error::Parse;
2465
                    errorMsg = errorMessage;
2466
                    return false;
2467
#endif
2468
453
                }
2469
2470
76
                return true;
2471
538
            }
Unexecuted instantiation: bool args::ArgumentParser::ParseLong<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>)
2472
2473
            template <typename It>
2474
            bool ParseShort(It &it, It end)
2475
458
            {
2476
458
                const auto &chunk = *it;
2477
458
                const auto argchunk = chunk.substr(shortprefix.size());
2478
7.06k
                for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit)
2479
6.83k
                {
2480
6.83k
                    const auto arg = *argit;
2481
2482
6.83k
                    if (auto flag = Match(arg))
2483
6.60k
                    {
2484
6.60k
                        const std::string value(argit + 1, std::end(argchunk));
2485
6.60k
                        std::vector<std::string> values;
2486
6.60k
                        const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end,
2487
6.60k
                                                                         allowSeparateShortValue, allowJoinedShortValue,
2488
6.60k
                                                                         !value.empty(), value, !value.empty(), values);
2489
2490
6.60k
                        if (!errorMessage.empty())
2491
0
                        {
2492
0
#ifndef ARGS_NOEXCEPT
2493
0
                            throw ParseError(errorMessage);
2494
#else
2495
                            error = Error::Parse;
2496
                            errorMsg = errorMessage;
2497
                            return false;
2498
#endif
2499
0
                        }
2500
2501
6.60k
                        if (!readCompletion)
2502
6.60k
                        {
2503
6.60k
                            flag->ParseValue(values);
2504
6.60k
                        }
2505
2506
6.60k
                        if (flag->KickOut())
2507
0
                        {
2508
0
                            ++it;
2509
0
                            return false;
2510
0
                        }
2511
2512
6.60k
                        if (!values.empty())
2513
0
                        {
2514
0
                            break;
2515
0
                        }
2516
6.60k
                    } else
2517
228
                    {
2518
228
                        const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'");
2519
228
#ifndef ARGS_NOEXCEPT
2520
228
                        throw ParseError(errorMessage);
2521
#else
2522
                        error = Error::Parse;
2523
                        errorMsg = errorMessage;
2524
                        return false;
2525
#endif
2526
228
                    }
2527
6.83k
                }
2528
2529
230
                return true;
2530
458
            }
bool args::ArgumentParser::ParseShort<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>)
Line
Count
Source
2475
458
            {
2476
458
                const auto &chunk = *it;
2477
458
                const auto argchunk = chunk.substr(shortprefix.size());
2478
7.06k
                for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit)
2479
6.83k
                {
2480
6.83k
                    const auto arg = *argit;
2481
2482
6.83k
                    if (auto flag = Match(arg))
2483
6.60k
                    {
2484
6.60k
                        const std::string value(argit + 1, std::end(argchunk));
2485
6.60k
                        std::vector<std::string> values;
2486
6.60k
                        const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end,
2487
6.60k
                                                                         allowSeparateShortValue, allowJoinedShortValue,
2488
6.60k
                                                                         !value.empty(), value, !value.empty(), values);
2489
2490
6.60k
                        if (!errorMessage.empty())
2491
0
                        {
2492
0
#ifndef ARGS_NOEXCEPT
2493
0
                            throw ParseError(errorMessage);
2494
#else
2495
                            error = Error::Parse;
2496
                            errorMsg = errorMessage;
2497
                            return false;
2498
#endif
2499
0
                        }
2500
2501
6.60k
                        if (!readCompletion)
2502
6.60k
                        {
2503
6.60k
                            flag->ParseValue(values);
2504
6.60k
                        }
2505
2506
6.60k
                        if (flag->KickOut())
2507
0
                        {
2508
0
                            ++it;
2509
0
                            return false;
2510
0
                        }
2511
2512
6.60k
                        if (!values.empty())
2513
0
                        {
2514
0
                            break;
2515
0
                        }
2516
6.60k
                    } else
2517
228
                    {
2518
228
                        const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'");
2519
228
#ifndef ARGS_NOEXCEPT
2520
228
                        throw ParseError(errorMessage);
2521
#else
2522
                        error = Error::Parse;
2523
                        errorMsg = errorMessage;
2524
                        return false;
2525
#endif
2526
228
                    }
2527
6.83k
                }
2528
2529
230
                return true;
2530
458
            }
Unexecuted instantiation: bool args::ArgumentParser::ParseShort<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>&, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>)
2531
2532
            bool AddCompletionReply(const std::string &cur, const std::string &choice)
2533
0
            {
2534
0
                if (cur.empty() || choice.find(cur) == 0)
2535
0
                {
2536
0
                    if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos)
2537
0
                    {
2538
0
                        completion->reply.push_back(choice.substr(choice.find(longseparator) + 1));
2539
0
                    } else
2540
0
                    {
2541
0
                        completion->reply.push_back(choice);
2542
0
                    }
2543
0
                    return true;
2544
0
                }
2545
2546
0
                return false;
2547
0
            }
2548
2549
            template <typename It>
2550
            bool Complete(It it, It end)
2551
1.18k
            {
2552
1.18k
                auto nextIt = it;
2553
1.18k
                if (!readCompletion || (++nextIt != end))
2554
1.18k
                {
2555
1.18k
                    return false;
2556
1.18k
                }
2557
2558
0
                const auto &chunk = *it;
2559
0
                auto pos = GetNextPositional();
2560
0
                std::vector<Command *> commands = GetCommands();
2561
0
                const auto optionType = ParseOption(chunk, true);
2562
2563
0
                if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
2564
0
                {
2565
0
                    for (auto &cmd : commands)
2566
0
                    {
2567
0
                        if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2568
0
                        {
2569
0
                            AddCompletionReply(chunk, cmd->Name());
2570
0
                        }
2571
0
                    }
2572
0
                } else
2573
0
                {
2574
0
                    bool hasPositionalCompletion = true;
2575
2576
0
                    if (!commands.empty())
2577
0
                    {
2578
0
                        for (auto &cmd : commands)
2579
0
                        {
2580
0
                            if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2581
0
                            {
2582
0
                                AddCompletionReply(chunk, cmd->Name());
2583
0
                            }
2584
0
                        }
2585
0
                    } else if (pos)
2586
0
                    {
2587
0
                        if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2588
0
                        {
2589
0
                            auto choices = pos->HelpChoices(helpParams);
2590
0
                            hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
2591
0
                            for (auto &choice : choices)
2592
0
                            {
2593
0
                                AddCompletionReply(chunk, choice);
2594
0
                            }
2595
0
                        }
2596
0
                    }
2597
2598
0
                    if (hasPositionalCompletion)
2599
0
                    {
2600
0
                        auto flags = GetAllFlags();
2601
0
                        for (auto flag : flags)
2602
0
                        {
2603
0
                            if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None)
2604
0
                            {
2605
0
                                continue;
2606
0
                            }
2607
2608
0
                            auto &matcher = flag->GetMatcher();
2609
0
                            if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix)))
2610
0
                            {
2611
0
                                for (auto &flagName : matcher.GetFlagStrings())
2612
0
                                {
2613
0
                                    if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix)))
2614
0
                                    {
2615
0
                                        break;
2616
0
                                    }
2617
0
                                }
2618
0
                            }
2619
0
                        }
2620
2621
0
                        if (optionType == OptionType::LongFlag && allowJoinedLongValue)
2622
0
                        {
2623
0
                            const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
2624
0
                            if (separator != chunk.npos)
2625
0
                            {
2626
0
                                std::string arg(chunk, 0, separator);
2627
0
                                if (auto flag = this->Match(arg.substr(longprefix.size())))
2628
0
                                {
2629
0
                                    for (auto &choice : flag->HelpChoices(helpParams))
2630
0
                                    {
2631
0
                                        AddCompletionReply(chunk, arg + longseparator + choice);
2632
0
                                    }
2633
0
                                }
2634
0
                            }
2635
0
                        } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
2636
0
                        {
2637
0
                            if (chunk.size() > shortprefix.size() + 1)
2638
0
                            {
2639
0
                                auto arg = chunk.at(shortprefix.size());
2640
                                //TODO: support -abcVALUE where a and b take no value
2641
0
                                if (auto flag = this->Match(arg))
2642
0
                                {
2643
0
                                    for (auto &choice : flag->HelpChoices(helpParams))
2644
0
                                    {
2645
0
                                        AddCompletionReply(chunk, shortprefix + arg + choice);
2646
0
                                    }
2647
0
                                }
2648
0
                            }
2649
0
                        }
2650
0
                    }
2651
0
                }
2652
2653
0
#ifndef ARGS_NOEXCEPT
2654
0
                throw Completion(completion->Get());
2655
#else
2656
                return true;
2657
#endif
2658
1.18k
            }
bool args::ArgumentParser::Complete<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>)
Line
Count
Source
2551
1.18k
            {
2552
1.18k
                auto nextIt = it;
2553
1.18k
                if (!readCompletion || (++nextIt != end))
2554
1.18k
                {
2555
1.18k
                    return false;
2556
1.18k
                }
2557
2558
0
                const auto &chunk = *it;
2559
0
                auto pos = GetNextPositional();
2560
0
                std::vector<Command *> commands = GetCommands();
2561
0
                const auto optionType = ParseOption(chunk, true);
2562
2563
0
                if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
2564
0
                {
2565
0
                    for (auto &cmd : commands)
2566
0
                    {
2567
0
                        if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2568
0
                        {
2569
0
                            AddCompletionReply(chunk, cmd->Name());
2570
0
                        }
2571
0
                    }
2572
0
                } else
2573
0
                {
2574
0
                    bool hasPositionalCompletion = true;
2575
2576
0
                    if (!commands.empty())
2577
0
                    {
2578
0
                        for (auto &cmd : commands)
2579
0
                        {
2580
0
                            if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2581
0
                            {
2582
0
                                AddCompletionReply(chunk, cmd->Name());
2583
0
                            }
2584
0
                        }
2585
0
                    } else if (pos)
2586
0
                    {
2587
0
                        if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
2588
0
                        {
2589
0
                            auto choices = pos->HelpChoices(helpParams);
2590
0
                            hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
2591
0
                            for (auto &choice : choices)
2592
0
                            {
2593
0
                                AddCompletionReply(chunk, choice);
2594
0
                            }
2595
0
                        }
2596
0
                    }
2597
2598
0
                    if (hasPositionalCompletion)
2599
0
                    {
2600
0
                        auto flags = GetAllFlags();
2601
0
                        for (auto flag : flags)
2602
0
                        {
2603
0
                            if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None)
2604
0
                            {
2605
0
                                continue;
2606
0
                            }
2607
2608
0
                            auto &matcher = flag->GetMatcher();
2609
0
                            if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix)))
2610
0
                            {
2611
0
                                for (auto &flagName : matcher.GetFlagStrings())
2612
0
                                {
2613
0
                                    if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix)))
2614
0
                                    {
2615
0
                                        break;
2616
0
                                    }
2617
0
                                }
2618
0
                            }
2619
0
                        }
2620
2621
0
                        if (optionType == OptionType::LongFlag && allowJoinedLongValue)
2622
0
                        {
2623
0
                            const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
2624
0
                            if (separator != chunk.npos)
2625
0
                            {
2626
0
                                std::string arg(chunk, 0, separator);
2627
0
                                if (auto flag = this->Match(arg.substr(longprefix.size())))
2628
0
                                {
2629
0
                                    for (auto &choice : flag->HelpChoices(helpParams))
2630
0
                                    {
2631
0
                                        AddCompletionReply(chunk, arg + longseparator + choice);
2632
0
                                    }
2633
0
                                }
2634
0
                            }
2635
0
                        } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
2636
0
                        {
2637
0
                            if (chunk.size() > shortprefix.size() + 1)
2638
0
                            {
2639
0
                                auto arg = chunk.at(shortprefix.size());
2640
                                //TODO: support -abcVALUE where a and b take no value
2641
0
                                if (auto flag = this->Match(arg))
2642
0
                                {
2643
0
                                    for (auto &choice : flag->HelpChoices(helpParams))
2644
0
                                    {
2645
0
                                        AddCompletionReply(chunk, shortprefix + arg + choice);
2646
0
                                    }
2647
0
                                }
2648
0
                            }
2649
0
                        }
2650
0
                    }
2651
0
                }
2652
2653
0
#ifndef ARGS_NOEXCEPT
2654
0
                throw Completion(completion->Get());
2655
#else
2656
                return true;
2657
#endif
2658
1.18k
            }
Unexecuted instantiation: bool args::ArgumentParser::Complete<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>)
2659
2660
            template <typename It>
2661
            It Parse(It begin, It end)
2662
906
            {
2663
906
                bool terminated = false;
2664
906
                std::vector<Command *> commands = GetCommands();
2665
2666
                // Check all arg chunks
2667
1.90k
                for (auto it = begin; it != end; ++it)
2668
1.18k
                {
2669
1.18k
                    if (Complete(it, end))
2670
0
                    {
2671
0
                        return end;
2672
0
                    }
2673
2674
1.18k
                    const auto &chunk = *it;
2675
2676
1.18k
                    if (!terminated && chunk == terminator)
2677
2
                    {
2678
2
                        terminated = true;
2679
1.17k
                    } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag)
2680
538
                    {
2681
538
                        if (!ParseLong(it, end))
2682
0
                        {
2683
0
                            return it;
2684
0
                        }
2685
640
                    } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag)
2686
458
                    {
2687
458
                        if (!ParseShort(it, end))
2688
0
                        {
2689
0
                            return it;
2690
0
                        }
2691
458
                    } else if (!terminated && !commands.empty())
2692
0
                    {
2693
0
                        auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; });
2694
0
                        if (itCommand == commands.end())
2695
0
                        {
2696
0
                            const std::string errorMessage("Unknown command: " + chunk);
2697
0
#ifndef ARGS_NOEXCEPT
2698
0
                            throw ParseError(errorMessage);
2699
#else
2700
                            error = Error::Parse;
2701
                            errorMsg = errorMessage;
2702
                            return it;
2703
#endif
2704
0
                        }
2705
2706
0
                        SelectCommand(*itCommand);
2707
2708
0
                        if (const auto &coroutine = GetCoroutine())
2709
0
                        {
2710
0
                            ++it;
2711
0
                            RaiiSubparser coro(*this, std::vector<std::string>(it, end));
2712
0
                            coroutine(coro.Parser());
2713
#ifdef ARGS_NOEXCEPT
2714
                            error = GetError();
2715
                            if (error != Error::None)
2716
                            {
2717
                                return end;
2718
                            }
2719
2720
                            if (!coro.Parser().IsParsed())
2721
                            {
2722
                                error = Error::Usage;
2723
                                return end;
2724
                            }
2725
#else
2726
0
                            if (!coro.Parser().IsParsed())
2727
0
                            {
2728
0
                                throw UsageError("Subparser::Parse was not called");
2729
0
                            }
2730
0
#endif
2731
2732
0
                            break;
2733
0
                        }
2734
2735
0
                        commands = GetCommands();
2736
0
                    } else
2737
182
                    {
2738
182
                        auto pos = GetNextPositional();
2739
182
                        if (pos)
2740
0
                        {
2741
0
                            pos->ParseValue(chunk);
2742
2743
0
                            if (pos->KickOut())
2744
0
                            {
2745
0
                                return ++it;
2746
0
                            }
2747
0
                        } else
2748
182
                        {
2749
182
                            const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk);
2750
182
#ifndef ARGS_NOEXCEPT
2751
182
                            throw ParseError(errorMessage);
2752
#else
2753
                            error = Error::Parse;
2754
                            errorMsg = errorMessage;
2755
                            return it;
2756
#endif
2757
182
                        }
2758
182
                    }
2759
2760
998
                    if (!readCompletion && completion != nullptr && completion->Matched())
2761
0
                    {
2762
#ifdef ARGS_NOEXCEPT
2763
                        error = Error::Completion;
2764
#endif
2765
0
                        readCompletion = true;
2766
0
                        ++it;
2767
0
                        const auto argsLeft = static_cast<size_t>(std::distance(it, end));
2768
0
                        if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft)
2769
0
                        {
2770
0
#ifndef ARGS_NOEXCEPT
2771
0
                            throw Completion("");
2772
0
#endif
2773
0
                        }
2774
2775
0
                        std::vector<std::string> curArgs(++it, end);
2776
0
                        curArgs.resize(completion->cword);
2777
2778
0
                        if (completion->syntax == "bash")
2779
0
                        {
2780
                            // bash tokenizes --flag=value as --flag=value
2781
0
                            for (size_t idx = 0; idx < curArgs.size(); )
2782
0
                            {
2783
0
                                if (idx > 0 && curArgs[idx] == "=")
2784
0
                                {
2785
0
                                    curArgs[idx - 1] += "=";
2786
                                    // Avoid warnings from -Wsign-conversion
2787
0
                                    const auto signedIdx = static_cast<std::ptrdiff_t>(idx);
2788
0
                                    if (idx + 1 < curArgs.size())
2789
0
                                    {
2790
0
                                        curArgs[idx - 1] += curArgs[idx + 1];
2791
0
                                        curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2);
2792
0
                                    } else
2793
0
                                    {
2794
0
                                        curArgs.erase(curArgs.begin() + signedIdx);
2795
0
                                    }
2796
0
                                } else
2797
0
                                {
2798
0
                                    ++idx;
2799
0
                                }
2800
0
                            }
2801
2802
0
                        }
2803
0
#ifndef ARGS_NOEXCEPT
2804
0
                        try
2805
0
                        {
2806
0
                            Parse(curArgs.begin(), curArgs.end());
2807
0
                            throw Completion("");
2808
0
                        }
2809
0
                        catch (Completion &)
2810
0
                        {
2811
0
                            throw;
2812
0
                        }
2813
0
                        catch (args::Error&)
2814
0
                        {
2815
0
                            throw Completion("");
2816
0
                        }
2817
#else
2818
                        return Parse(curArgs.begin(), curArgs.end());
2819
#endif
2820
0
                    }
2821
998
                }
2822
2823
724
                Validate(shortprefix, longprefix);
2824
724
                return end;
2825
906
            }
std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> args::ArgumentParser::Parse<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>)
Line
Count
Source
2662
906
            {
2663
906
                bool terminated = false;
2664
906
                std::vector<Command *> commands = GetCommands();
2665
2666
                // Check all arg chunks
2667
1.90k
                for (auto it = begin; it != end; ++it)
2668
1.18k
                {
2669
1.18k
                    if (Complete(it, end))
2670
0
                    {
2671
0
                        return end;
2672
0
                    }
2673
2674
1.18k
                    const auto &chunk = *it;
2675
2676
1.18k
                    if (!terminated && chunk == terminator)
2677
2
                    {
2678
2
                        terminated = true;
2679
1.17k
                    } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag)
2680
538
                    {
2681
538
                        if (!ParseLong(it, end))
2682
0
                        {
2683
0
                            return it;
2684
0
                        }
2685
640
                    } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag)
2686
458
                    {
2687
458
                        if (!ParseShort(it, end))
2688
0
                        {
2689
0
                            return it;
2690
0
                        }
2691
458
                    } else if (!terminated && !commands.empty())
2692
0
                    {
2693
0
                        auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; });
2694
0
                        if (itCommand == commands.end())
2695
0
                        {
2696
0
                            const std::string errorMessage("Unknown command: " + chunk);
2697
0
#ifndef ARGS_NOEXCEPT
2698
0
                            throw ParseError(errorMessage);
2699
#else
2700
                            error = Error::Parse;
2701
                            errorMsg = errorMessage;
2702
                            return it;
2703
#endif
2704
0
                        }
2705
2706
0
                        SelectCommand(*itCommand);
2707
2708
0
                        if (const auto &coroutine = GetCoroutine())
2709
0
                        {
2710
0
                            ++it;
2711
0
                            RaiiSubparser coro(*this, std::vector<std::string>(it, end));
2712
0
                            coroutine(coro.Parser());
2713
#ifdef ARGS_NOEXCEPT
2714
                            error = GetError();
2715
                            if (error != Error::None)
2716
                            {
2717
                                return end;
2718
                            }
2719
2720
                            if (!coro.Parser().IsParsed())
2721
                            {
2722
                                error = Error::Usage;
2723
                                return end;
2724
                            }
2725
#else
2726
0
                            if (!coro.Parser().IsParsed())
2727
0
                            {
2728
0
                                throw UsageError("Subparser::Parse was not called");
2729
0
                            }
2730
0
#endif
2731
2732
0
                            break;
2733
0
                        }
2734
2735
0
                        commands = GetCommands();
2736
0
                    } else
2737
182
                    {
2738
182
                        auto pos = GetNextPositional();
2739
182
                        if (pos)
2740
0
                        {
2741
0
                            pos->ParseValue(chunk);
2742
2743
0
                            if (pos->KickOut())
2744
0
                            {
2745
0
                                return ++it;
2746
0
                            }
2747
0
                        } else
2748
182
                        {
2749
182
                            const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk);
2750
182
#ifndef ARGS_NOEXCEPT
2751
182
                            throw ParseError(errorMessage);
2752
#else
2753
                            error = Error::Parse;
2754
                            errorMsg = errorMessage;
2755
                            return it;
2756
#endif
2757
182
                        }
2758
182
                    }
2759
2760
998
                    if (!readCompletion && completion != nullptr && completion->Matched())
2761
0
                    {
2762
#ifdef ARGS_NOEXCEPT
2763
                        error = Error::Completion;
2764
#endif
2765
0
                        readCompletion = true;
2766
0
                        ++it;
2767
0
                        const auto argsLeft = static_cast<size_t>(std::distance(it, end));
2768
0
                        if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft)
2769
0
                        {
2770
0
#ifndef ARGS_NOEXCEPT
2771
0
                            throw Completion("");
2772
0
#endif
2773
0
                        }
2774
2775
0
                        std::vector<std::string> curArgs(++it, end);
2776
0
                        curArgs.resize(completion->cword);
2777
2778
0
                        if (completion->syntax == "bash")
2779
0
                        {
2780
                            // bash tokenizes --flag=value as --flag=value
2781
0
                            for (size_t idx = 0; idx < curArgs.size(); )
2782
0
                            {
2783
0
                                if (idx > 0 && curArgs[idx] == "=")
2784
0
                                {
2785
0
                                    curArgs[idx - 1] += "=";
2786
                                    // Avoid warnings from -Wsign-conversion
2787
0
                                    const auto signedIdx = static_cast<std::ptrdiff_t>(idx);
2788
0
                                    if (idx + 1 < curArgs.size())
2789
0
                                    {
2790
0
                                        curArgs[idx - 1] += curArgs[idx + 1];
2791
0
                                        curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2);
2792
0
                                    } else
2793
0
                                    {
2794
0
                                        curArgs.erase(curArgs.begin() + signedIdx);
2795
0
                                    }
2796
0
                                } else
2797
0
                                {
2798
0
                                    ++idx;
2799
0
                                }
2800
0
                            }
2801
2802
0
                        }
2803
0
#ifndef ARGS_NOEXCEPT
2804
0
                        try
2805
0
                        {
2806
0
                            Parse(curArgs.begin(), curArgs.end());
2807
0
                            throw Completion("");
2808
0
                        }
2809
0
                        catch (Completion &)
2810
0
                        {
2811
0
                            throw;
2812
0
                        }
2813
0
                        catch (args::Error&)
2814
0
                        {
2815
0
                            throw Completion("");
2816
0
                        }
2817
#else
2818
                        return Parse(curArgs.begin(), curArgs.end());
2819
#endif
2820
0
                    }
2821
998
                }
2822
2823
724
                Validate(shortprefix, longprefix);
2824
724
                return end;
2825
906
            }
Unexecuted instantiation: std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> args::ArgumentParser::Parse<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>)
2826
2827
        public:
2828
            HelpParams helpParams;
2829
2830
            ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string())
2831
906
            {
2832
906
                Description(description_);
2833
906
                Epilog(epilog_);
2834
906
                LongPrefix("--");
2835
906
                ShortPrefix("-");
2836
906
                LongSeparator("=");
2837
906
                Terminator("--");
2838
906
                SetArgumentSeparations(true, true, true, true);
2839
906
                matched = true;
2840
906
            }
2841
2842
            void AddCompletion(CompletionFlag &completionFlag)
2843
0
            {
2844
0
                completion = &completionFlag;
2845
0
                Add(completionFlag);
2846
0
            }
2847
2848
            /** The program name for help generation
2849
             */
2850
            const std::string &Prog() const
2851
0
            { return helpParams.programName; }
2852
            /** The program name for help generation
2853
             */
2854
            void Prog(const std::string &prog_)
2855
0
            { this->helpParams.programName = prog_; }
2856
2857
            /** The prefix for long flags
2858
             */
2859
            const std::string &LongPrefix() const
2860
0
            { return longprefix; }
2861
            /** The prefix for long flags
2862
             */
2863
            void LongPrefix(const std::string &longprefix_)
2864
906
            {
2865
906
                this->longprefix = longprefix_;
2866
906
                this->helpParams.longPrefix = longprefix_;
2867
906
            }
2868
2869
            /** The prefix for short flags
2870
             */
2871
            const std::string &ShortPrefix() const
2872
0
            { return shortprefix; }
2873
            /** The prefix for short flags
2874
             */
2875
            void ShortPrefix(const std::string &shortprefix_)
2876
906
            {
2877
906
                this->shortprefix = shortprefix_;
2878
906
                this->helpParams.shortPrefix = shortprefix_;
2879
906
            }
2880
2881
            /** The separator for long flags
2882
             */
2883
            const std::string &LongSeparator() const
2884
0
            { return longseparator; }
2885
            /** The separator for long flags
2886
             */
2887
            void LongSeparator(const std::string &longseparator_)
2888
906
            {
2889
906
                if (longseparator_.empty())
2890
0
                {
2891
0
                    const std::string errorMessage("longseparator can not be set to empty");
2892
#ifdef ARGS_NOEXCEPT
2893
                    error = Error::Usage;
2894
                    errorMsg = errorMessage;
2895
#else
2896
0
                    throw UsageError(errorMessage);
2897
0
#endif
2898
0
                } else
2899
906
                {
2900
906
                    this->longseparator = longseparator_;
2901
906
                    this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " ";
2902
906
                }
2903
906
            }
2904
2905
            /** The terminator that forcibly separates flags from positionals
2906
             */
2907
            const std::string &Terminator() const
2908
0
            { return terminator; }
2909
            /** The terminator that forcibly separates flags from positionals
2910
             */
2911
            void Terminator(const std::string &terminator_)
2912
906
            { this->terminator = terminator_; }
2913
2914
            /** Get the current argument separation parameters.
2915
             *
2916
             * See SetArgumentSeparations for details on what each one means.
2917
             */
2918
            void GetArgumentSeparations(
2919
                bool &allowJoinedShortValue_,
2920
                bool &allowJoinedLongValue_,
2921
                bool &allowSeparateShortValue_,
2922
                bool &allowSeparateLongValue_) const
2923
0
            {
2924
0
                allowJoinedShortValue_ = this->allowJoinedShortValue;
2925
0
                allowJoinedLongValue_ = this->allowJoinedLongValue;
2926
0
                allowSeparateShortValue_ = this->allowSeparateShortValue;
2927
0
                allowSeparateLongValue_ = this->allowSeparateLongValue;
2928
0
            }
2929
2930
            /** Change allowed option separation.
2931
             *
2932
             * \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)
2933
             * \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)
2934
             * \param allowSeparateShortValue_ Allow a short flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field)
2935
             * \param allowSeparateLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field)
2936
             */
2937
            void SetArgumentSeparations(
2938
                const bool allowJoinedShortValue_,
2939
                const bool allowJoinedLongValue_,
2940
                const bool allowSeparateShortValue_,
2941
                const bool allowSeparateLongValue_)
2942
906
            {
2943
906
                this->allowJoinedShortValue = allowJoinedShortValue_;
2944
906
                this->allowJoinedLongValue = allowJoinedLongValue_;
2945
906
                this->allowSeparateShortValue = allowSeparateShortValue_;
2946
906
                this->allowSeparateLongValue = allowSeparateLongValue_;
2947
2948
906
                this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " ";
2949
906
                this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " ";
2950
906
            }
2951
2952
            /** Pass the help menu into an ostream
2953
             */
2954
            void Help(std::ostream &help_) const
2955
0
            {
2956
0
                auto &command = SelectedCommand();
2957
0
                const auto &commandDescription = command.Description().empty() ? command.Help() : command.Description();
2958
0
                const auto description_text = Wrap(commandDescription, helpParams.width - helpParams.descriptionindent);
2959
0
                const auto epilog_text = Wrap(command.Epilog(), helpParams.width - helpParams.descriptionindent);
2960
0
2961
0
                const bool hasoptions = command.HasFlag();
2962
0
                const bool hasarguments = command.HasPositional();
2963
0
2964
0
                std::vector<std::string> prognameline;
2965
0
                prognameline.push_back(helpParams.usageString);
2966
0
                prognameline.push_back(Prog());
2967
0
                auto commandProgLine = command.GetProgramLine(helpParams);
2968
0
                prognameline.insert(prognameline.end(), commandProgLine.begin(), commandProgLine.end());
2969
0
2970
0
                const auto proglines = Wrap(prognameline.begin(), prognameline.end(),
2971
0
                                            helpParams.width - (helpParams.progindent + helpParams.progtailindent),
2972
0
                                            helpParams.width - helpParams.progindent);
2973
0
                auto progit = std::begin(proglines);
2974
0
                if (progit != std::end(proglines))
2975
0
                {
2976
0
                    help_ << std::string(helpParams.progindent, ' ') << *progit << '\n';
2977
0
                    ++progit;
2978
0
                }
2979
0
                for (; progit != std::end(proglines); ++progit)
2980
0
                {
2981
0
                    help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n';
2982
0
                }
2983
0
2984
0
                help_ << '\n';
2985
0
2986
0
                if (!description_text.empty())
2987
0
                {
2988
0
                    for (const auto &line: description_text)
2989
0
                    {
2990
0
                        help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
2991
0
                    }
2992
0
                    help_ << "\n";
2993
0
                }
2994
0
2995
0
                bool lastDescriptionIsNewline = false;
2996
0
2997
0
                if (!helpParams.optionsString.empty())
2998
0
                {
2999
0
                    help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n";
3000
0
                }
3001
0
3002
0
                for (const auto &desc: command.GetDescription(helpParams, 0))
3003
0
                {
3004
0
                    lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty();
3005
0
                    const auto groupindent = std::get<2>(desc) * helpParams.eachgroupindent;
3006
0
                    const auto flags = Wrap(std::get<0>(desc), helpParams.width - (helpParams.flagindent + helpParams.helpindent + helpParams.gutter));
3007
0
                    const auto info = Wrap(std::get<1>(desc), helpParams.width - (helpParams.helpindent + groupindent));
3008
0
3009
0
                    std::string::size_type flagssize = 0;
3010
0
                    for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit)
3011
0
                    {
3012
0
                        if (flagsit != std::begin(flags))
3013
0
                        {
3014
0
                            help_ << '\n';
3015
0
                        }
3016
0
                        help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit;
3017
0
                        flagssize = Glyphs(*flagsit);
3018
0
                    }
3019
0
3020
0
                    auto infoit = std::begin(info);
3021
0
                    // groupindent is on both sides of this inequality, and therefore can be removed
3022
0
                    if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription)
3023
0
                    {
3024
0
                        help_ << '\n';
3025
0
                    } else
3026
0
                    {
3027
0
                        // groupindent is on both sides of the minus sign, and therefore doesn't actually need to be in here
3028
0
                        help_ << std::string(helpParams.helpindent - (helpParams.flagindent + flagssize), ' ') << *infoit << '\n';
3029
0
                        ++infoit;
3030
0
                    }
3031
0
                    for (; infoit != std::end(info); ++infoit)
3032
0
                    {
3033
0
                        help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n';
3034
0
                    }
3035
0
                }
3036
0
                if (hasoptions && hasarguments && helpParams.showTerminator)
3037
0
                {
3038
0
                    lastDescriptionIsNewline = false;
3039
0
                    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))
3040
0
                    {
3041
0
                        help_ << std::string(helpParams.flagindent, ' ') << item << '\n';
3042
0
                    }
3043
0
                }
3044
0
3045
0
                if (!lastDescriptionIsNewline)
3046
0
                {
3047
0
                    help_ << "\n";
3048
0
                }
3049
0
3050
0
                for (const auto &line: epilog_text)
3051
0
                {
3052
0
                    help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
3053
0
                }
3054
0
            }
3055
3056
            /** Generate a help menu as a string.
3057
             *
3058
             * \return the help text as a single string
3059
             */
3060
            std::string Help() const
3061
0
            {
3062
0
                std::ostringstream help_;
3063
0
                Help(help_);
3064
0
                return help_.str();
3065
0
            }
3066
3067
            virtual void Reset() noexcept override
3068
906
            {
3069
906
                Command::Reset();
3070
906
                matched = true;
3071
906
                readCompletion = false;
3072
906
            }
3073
3074
            /** Parse all arguments.
3075
             *
3076
             * \param begin an iterator to the beginning of the argument list
3077
             * \param end an iterator to the past-the-end element of the argument list
3078
             * \return the iterator after the last parsed value.  Only useful for kick-out
3079
             */
3080
            template <typename It>
3081
            It ParseArgs(It begin, It end)
3082
906
            {
3083
                // Reset all Matched statuses and errors
3084
906
                Reset();
3085
#ifdef ARGS_NOEXCEPT
3086
                error = GetError();
3087
                if (error != Error::None)
3088
                {
3089
                    return end;
3090
                }
3091
#endif
3092
906
                return Parse(begin, end);
3093
906
            }
std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> args::ArgumentParser::ParseArgs<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>)
Line
Count
Source
3082
906
            {
3083
                // Reset all Matched statuses and errors
3084
906
                Reset();
3085
#ifdef ARGS_NOEXCEPT
3086
                error = GetError();
3087
                if (error != Error::None)
3088
                {
3089
                    return end;
3090
                }
3091
#endif
3092
906
                return Parse(begin, end);
3093
906
            }
Unexecuted instantiation: std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> args::ArgumentParser::ParseArgs<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>)
3094
3095
            /** Parse all arguments.
3096
             *
3097
             * \param args an iterable of the arguments
3098
             * \return the iterator after the last parsed value.  Only useful for kick-out
3099
             */
3100
            template <typename T>
3101
            auto ParseArgs(const T &args) -> decltype(std::begin(args))
3102
0
            {
3103
0
                return ParseArgs(std::begin(args), std::end(args));
3104
0
            }
3105
3106
            /** Convenience function to parse the CLI from argc and argv
3107
             *
3108
             * Just assigns the program name and vectorizes arguments for passing into ParseArgs()
3109
             *
3110
             * \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.
3111
             */
3112
            bool ParseCLI(const int argc, const char * const * argv)
3113
0
            {
3114
0
                if (Prog().empty())
3115
0
                {
3116
0
                    Prog(argv[0]);
3117
0
                }
3118
0
                const std::vector<std::string> args(argv + 1, argv + argc);
3119
0
                return ParseArgs(args) == std::end(args);
3120
0
            }
3121
            
3122
            template <typename T>
3123
            bool ParseCLI(const T &args)
3124
            {
3125
                return ParseArgs(args) == std::end(args);
3126
            }
3127
    };
3128
3129
    inline Command::RaiiSubparser::RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_)
3130
0
        : command(parser_.SelectedCommand()), parser(std::move(args_), parser_, command, parser_.helpParams), oldSubparser(command.subparser)
3131
0
    {
3132
0
        command.subparser = &parser;
3133
0
    }
3134
3135
0
    inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams &params_): command(command_), parser(command, params_), oldSubparser(command.subparser)
3136
0
    {
3137
0
        command.subparser = &parser;
3138
0
    }
3139
3140
    inline void Subparser::Parse()
3141
0
    {
3142
0
        isParsed = true;
3143
0
        Reset();
3144
0
        command.subparserDescription = GetDescription(helpParams, 0);
3145
0
        command.subparserHasFlag = HasFlag();
3146
0
        command.subparserHasPositional = HasPositional();
3147
0
        command.subparserHasCommand = HasCommand();
3148
0
        command.subparserProgramLine = GetProgramLine(helpParams);
3149
0
        if (parser == nullptr)
3150
0
        {
3151
0
#ifndef ARGS_NOEXCEPT
3152
0
            throw args::SubparserError();
3153
0
#else
3154
0
            error = Error::Subparser;
3155
0
            return;
3156
0
#endif
3157
0
        }
3158
0
3159
0
        auto it = parser->Parse(args.begin(), args.end());
3160
0
        command.Validate(parser->ShortPrefix(), parser->LongPrefix());
3161
0
        kicked.assign(it, args.end());
3162
0
3163
0
#ifdef ARGS_NOEXCEPT
3164
0
        command.subparserError = GetError();
3165
0
#endif
3166
0
    }
3167
3168
    inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser)
3169
0
    {
3170
0
        parser.Help(os);
3171
0
        return os;
3172
0
    }
3173
3174
    /** Boolean argument matcher
3175
     */
3176
    class Flag : public FlagBase
3177
    {
3178
        public:
3179
2.71k
            Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_)
3180
2.71k
            {
3181
2.71k
                group_.Add(*this);
3182
2.71k
            }
3183
3184
1.81k
            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)
3185
1.81k
            {
3186
1.81k
            }
3187
3188
0
            virtual ~Flag() {}
3189
3190
            /** Get whether this was matched
3191
             */
3192
            bool Get() const
3193
0
            {
3194
0
                return Matched();
3195
0
            }
3196
3197
            virtual Nargs NumberOfArguments() const noexcept override
3198
6.68k
            {
3199
6.68k
                return 0;
3200
6.68k
            }
3201
3202
            virtual void ParseValue(const std::vector<std::string>&) override
3203
6.65k
            {
3204
6.65k
            }
3205
    };
3206
3207
    /** Help flag class
3208
     *
3209
     * Works like a regular flag, but throws an instance of Help when it is matched
3210
     */
3211
    class HelpFlag : public Flag
3212
    {
3213
        public:
3214
906
            HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {}
3215
3216
0
            virtual ~HelpFlag() {}
3217
3218
            virtual void ParseValue(const std::vector<std::string> &)
3219
21
            {
3220
#ifdef ARGS_NOEXCEPT
3221
                    error = Error::Help;
3222
                    errorMsg = Name();
3223
#else
3224
21
                    throw Help(Name());
3225
21
#endif
3226
21
            }
3227
3228
            /** Get whether this was matched
3229
             */
3230
            bool Get() const noexcept
3231
0
            {
3232
0
                return Matched();
3233
0
            }
3234
    };
3235
3236
    /** A flag class that simply counts the number of times it's matched
3237
     */
3238
    class CounterFlag : public Flag
3239
    {
3240
        private:
3241
            const int startcount;
3242
            int count;
3243
3244
        public:
3245
            CounterFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const int startcount_ = 0, Options options_ = {}):
3246
0
                Flag(group_, name_, help_, std::move(matcher_), options_), startcount(startcount_), count(startcount_) {}
3247
3248
0
            virtual ~CounterFlag() {}
3249
3250
            virtual FlagBase *Match(const EitherFlag &arg) override
3251
0
            {
3252
0
                auto me = FlagBase::Match(arg);
3253
0
                if (me)
3254
0
                {
3255
0
                    ++count;
3256
0
                }
3257
0
                return me;
3258
0
            }
3259
3260
            /** Get the count
3261
             */
3262
            int &Get() noexcept
3263
0
            {
3264
0
                return count;
3265
0
            }
3266
3267
0
            int &operator *() noexcept {
3268
0
                return count;
3269
0
            }
3270
            
3271
0
            const int &operator *() const noexcept {
3272
0
                return count;
3273
0
            }
3274
3275
            virtual void Reset() noexcept override
3276
0
            {
3277
0
                FlagBase::Reset();
3278
0
                count = startcount;
3279
0
            }
3280
    };
3281
3282
    /** A flag class that calls a function when it's matched
3283
     */
3284
    class ActionFlag : public FlagBase
3285
    {
3286
        private:
3287
            std::function<void(const std::vector<std::string> &)> action;
3288
            Nargs nargs;
3289
3290
        public:
3291
            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_ = {}):
3292
                FlagBase(name_, help_, std::move(matcher_), options_), action(std::move(action_)), nargs(nargs_)
3293
0
            {
3294
0
                group_.Add(*this);
3295
0
            }
3296
3297
            ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void(const std::string &)> action_, Options options_ = {}):
3298
                FlagBase(name_, help_, std::move(matcher_), options_), nargs(1)
3299
0
            {
3300
0
                group_.Add(*this);
3301
0
                action = [action_](const std::vector<std::string> &a) { return action_(a.at(0)); };
3302
0
            }
3303
3304
            ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void()> action_, Options options_ = {}):
3305
                FlagBase(name_, help_, std::move(matcher_), options_), nargs(0)
3306
0
            {
3307
0
                group_.Add(*this);
3308
0
                action = [action_](const std::vector<std::string> &) { return action_(); };
3309
0
            }
3310
3311
            virtual Nargs NumberOfArguments() const noexcept override
3312
0
            { return nargs; }
3313
3314
            virtual void ParseValue(const std::vector<std::string> &value) override
3315
0
            { action(value); }
3316
    };
3317
3318
    /** A default Reader class for argument classes
3319
     *
3320
     * If destination type is assignable to std::string it uses an assignment to std::string.
3321
     * Otherwise ValueReader simply uses a std::istringstream to read into the destination type, and
3322
     * raises a ParseError if there are any characters left.
3323
     */
3324
    struct ValueReader
3325
    {
3326
        template <typename T>
3327
        typename std::enable_if<!std::is_assignable<T, std::string>::value, bool>::type
3328
        operator ()(const std::string &name, const std::string &value, T &destination)
3329
        {
3330
            std::istringstream ss(value);
3331
            bool failed = !(ss >> destination);
3332
3333
            if (!failed)
3334
            {
3335
                ss >> std::ws;
3336
            }
3337
3338
            if (ss.rdbuf()->in_avail() > 0 || failed)
3339
            {
3340
#ifdef ARGS_NOEXCEPT
3341
                (void)name;
3342
                return false;
3343
#else
3344
                std::ostringstream problem;
3345
                problem << "Argument '" << name << "' received invalid value type '" << value << "'";
3346
                throw ParseError(problem.str());
3347
#endif
3348
            }
3349
            return true;
3350
        }
3351
3352
        template <typename T>
3353
        typename std::enable_if<std::is_assignable<T, std::string>::value, bool>::type
3354
        operator()(const std::string &, const std::string &value, T &destination)
3355
        {
3356
            destination = value;
3357
            return true;
3358
        }
3359
    };
3360
3361
    /** An argument-accepting flag class
3362
     * 
3363
     * \tparam T the type to extract the argument as
3364
     * \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)
3365
     */
3366
    template <
3367
        typename T,
3368
        typename Reader = ValueReader>
3369
    class ValueFlag : public ValueFlagBase
3370
    {
3371
        protected:
3372
            T value;
3373
            T defaultValue;
3374
3375
            virtual std::string GetDefaultString(const HelpParams&) const override
3376
            {
3377
                return detail::ToString(defaultValue);
3378
            }
3379
3380
        private:
3381
            Reader reader;
3382
3383
        public:
3384
3385
            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_)
3386
            {
3387
                group_.Add(*this);
3388
            }
3389
3390
            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)
3391
            {
3392
            }
3393
3394
            ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): ValueFlag(group_, name_, help_, std::move(matcher_), T(), options_)
3395
            {
3396
            }
3397
3398
            virtual ~ValueFlag() {}
3399
3400
            virtual void ParseValue(const std::vector<std::string> &values_) override
3401
            {
3402
                const std::string &value_ = values_.at(0);
3403
3404
#ifdef ARGS_NOEXCEPT
3405
                if (!reader(name, value_, this->value))
3406
                {
3407
                    error = Error::Parse;
3408
                }
3409
#else
3410
                reader(name, value_, this->value);
3411
#endif
3412
            }
3413
3414
            virtual void Reset() noexcept override
3415
            {
3416
                ValueFlagBase::Reset();
3417
                value = defaultValue;
3418
            }
3419
3420
            /** Get the value
3421
             */
3422
            T &Get() noexcept
3423
            {
3424
                return value;
3425
            }
3426
3427
            /** Get the value
3428
             */
3429
            T &operator *() noexcept
3430
            {
3431
                return value;
3432
            }
3433
3434
            /** Get the value
3435
             */
3436
            const T &operator *() const noexcept
3437
            {
3438
                return value;
3439
            }
3440
3441
            /** Get the value
3442
             */
3443
            T *operator ->() noexcept
3444
            {
3445
                return &value;
3446
            }
3447
3448
            /** Get the value
3449
             */
3450
            const T *operator ->() const noexcept
3451
            {
3452
                return &value;
3453
            }
3454
3455
            /** Get the default value
3456
             */
3457
            const T &GetDefault() noexcept
3458
            {
3459
                return defaultValue;
3460
            }
3461
    };
3462
3463
    /** An optional argument-accepting flag class
3464
     *
3465
     * \tparam T the type to extract the argument as
3466
     * \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)
3467
     */
3468
    template <
3469
        typename T,
3470
        typename Reader = ValueReader>
3471
    class ImplicitValueFlag : public ValueFlag<T, Reader>
3472
    {
3473
        protected:
3474
            T implicitValue;
3475
3476
        public:
3477
3478
            ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {})
3479
                : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_)
3480
            {
3481
            }
3482
3483
            ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {})
3484
                : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_)
3485
            {
3486
            }
3487
3488
            ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_)
3489
                : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue()
3490
            {
3491
            }
3492
3493
            virtual ~ImplicitValueFlag() {}
3494
3495
            virtual Nargs NumberOfArguments() const noexcept override
3496
            {
3497
                return {0, 1};
3498
            }
3499
3500
            virtual void ParseValue(const std::vector<std::string> &value_) override
3501
            {
3502
                if (value_.empty())
3503
                {
3504
                    this->value = implicitValue;
3505
                } else
3506
                {
3507
                    ValueFlag<T, Reader>::ParseValue(value_);
3508
                }
3509
            }
3510
    };
3511
3512
    /** A variadic arguments accepting flag class
3513
     *
3514
     * \tparam T the type to extract the argument as
3515
     * \tparam List the list type that houses the values
3516
     * \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)
3517
     */
3518
    template <
3519
        typename T,
3520
        template <typename...> class List = detail::vector,
3521
        typename Reader = ValueReader>
3522
    class NargsValueFlag : public FlagBase
3523
    {
3524
        protected:
3525
3526
            List<T> values;
3527
            const List<T> defaultValues;
3528
            Nargs nargs;
3529
            Reader reader;
3530
3531
        public:
3532
3533
            typedef List<T> Container;
3534
            typedef T value_type;
3535
            typedef typename Container::allocator_type allocator_type;
3536
            typedef typename Container::pointer pointer;
3537
            typedef typename Container::const_pointer const_pointer;
3538
            typedef T& reference;
3539
            typedef const T& const_reference;
3540
            typedef typename Container::size_type size_type;
3541
            typedef typename Container::difference_type difference_type;
3542
            typedef typename Container::iterator iterator;
3543
            typedef typename Container::const_iterator const_iterator;
3544
            typedef std::reverse_iterator<iterator> reverse_iterator;
3545
            typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3546
3547
            NargsValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, const List<T> &defaultValues_ = {}, Options options_ = {})
3548
                : FlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_),nargs(nargs_)
3549
            {
3550
                group_.Add(*this);
3551
            }
3552
3553
            virtual ~NargsValueFlag() {}
3554
3555
            virtual Nargs NumberOfArguments() const noexcept override
3556
            {
3557
                return nargs;
3558
            }
3559
3560
            virtual void ParseValue(const std::vector<std::string> &values_) override
3561
            {
3562
                values.clear();
3563
3564
                for (const std::string &value : values_)
3565
                {
3566
                    T v;
3567
#ifdef ARGS_NOEXCEPT
3568
                    if (!reader(name, value, v))
3569
                    {
3570
                        error = Error::Parse;
3571
                    }
3572
#else
3573
                    reader(name, value, v);
3574
#endif
3575
                    values.insert(std::end(values), v);
3576
                }
3577
            }
3578
3579
            List<T> &Get() noexcept
3580
            {
3581
                return values;
3582
            }
3583
3584
            /** Get the value
3585
             */
3586
            List<T> &operator *() noexcept
3587
            {
3588
                return values;
3589
            }
3590
3591
            /** Get the values
3592
             */
3593
            const List<T> &operator *() const noexcept
3594
            {
3595
                return values;
3596
            }
3597
3598
            /** Get the values
3599
             */
3600
            List<T> *operator ->() noexcept
3601
            {
3602
                return &values;
3603
            }
3604
3605
            /** Get the values
3606
             */
3607
            const List<T> *operator ->() const noexcept
3608
            {
3609
                return &values;
3610
            }
3611
3612
            iterator begin() noexcept
3613
            {
3614
                return values.begin();
3615
            }
3616
3617
            const_iterator begin() const noexcept
3618
            {
3619
                return values.begin();
3620
            }
3621
3622
            const_iterator cbegin() const noexcept
3623
            {
3624
                return values.cbegin();
3625
            }
3626
3627
            iterator end() noexcept
3628
            {
3629
                return values.end();
3630
            }
3631
3632
            const_iterator end() const noexcept 
3633
            {
3634
                return values.end();
3635
            }
3636
3637
            const_iterator cend() const noexcept
3638
            {
3639
                return values.cend();
3640
            }
3641
3642
            virtual void Reset() noexcept override
3643
            {
3644
                FlagBase::Reset();
3645
                values = defaultValues;
3646
            }
3647
3648
            virtual FlagBase *Match(const EitherFlag &arg) override
3649
            {
3650
                const bool wasMatched = Matched();
3651
                auto me = FlagBase::Match(arg);
3652
                if (me && !wasMatched)
3653
                {
3654
                    values.clear();
3655
                }
3656
                return me;
3657
            }
3658
    };
3659
3660
    /** An argument-accepting flag class that pushes the found values into a list
3661
     * 
3662
     * \tparam T the type to extract the argument as
3663
     * \tparam List the list type that houses the values
3664
     * \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)
3665
     */
3666
    template <
3667
        typename T,
3668
        template <typename...> class List = detail::vector,
3669
        typename Reader = ValueReader>
3670
    class ValueFlagList : public ValueFlagBase
3671
    {
3672
        private:
3673
            using Container = List<T>;
3674
            Container values;
3675
            const Container defaultValues;
3676
            Reader reader;
3677
3678
        public:
3679
3680
            typedef T value_type;
3681
            typedef typename Container::allocator_type allocator_type;
3682
            typedef typename Container::pointer pointer;
3683
            typedef typename Container::const_pointer const_pointer;
3684
            typedef T& reference;
3685
            typedef const T& const_reference;
3686
            typedef typename Container::size_type size_type;
3687
            typedef typename Container::difference_type difference_type;
3688
            typedef typename Container::iterator iterator;
3689
            typedef typename Container::const_iterator const_iterator;
3690
            typedef std::reverse_iterator<iterator> reverse_iterator;
3691
            typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3692
3693
            ValueFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Container &defaultValues_ = Container(), Options options_ = {}):
3694
                ValueFlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_)
3695
            {
3696
                group_.Add(*this);
3697
            }
3698
3699
            virtual ~ValueFlagList() {}
3700
3701
            virtual void ParseValue(const std::vector<std::string> &values_) override
3702
            {
3703
                const std::string &value_ = values_.at(0);
3704
3705
                T v;
3706
#ifdef ARGS_NOEXCEPT
3707
                if (!reader(name, value_, v))
3708
                {
3709
                    error = Error::Parse;
3710
                }
3711
#else
3712
                reader(name, value_, v);
3713
#endif
3714
                values.insert(std::end(values), v);
3715
            }
3716
3717
            /** Get the values
3718
             */
3719
            Container &Get() noexcept
3720
            {
3721
                return values;
3722
            }
3723
3724
            /** Get the value
3725
             */
3726
            Container &operator *() noexcept
3727
            {
3728
                return values;
3729
            }
3730
3731
            /** Get the values
3732
             */
3733
            const Container &operator *() const noexcept
3734
            {
3735
                return values;
3736
            }
3737
3738
            /** Get the values
3739
             */
3740
            Container *operator ->() noexcept
3741
            {
3742
                return &values;
3743
            }
3744
3745
            /** Get the values
3746
             */
3747
            const Container *operator ->() const noexcept
3748
            {
3749
                return &values;
3750
            }
3751
3752
            virtual std::string Name() const override
3753
            {
3754
                return name + std::string("...");
3755
            }
3756
3757
            virtual void Reset() noexcept override
3758
            {
3759
                ValueFlagBase::Reset();
3760
                values = defaultValues;
3761
            }
3762
3763
            virtual FlagBase *Match(const EitherFlag &arg) override
3764
            {
3765
                const bool wasMatched = Matched();
3766
                auto me = FlagBase::Match(arg);
3767
                if (me && !wasMatched)
3768
                {
3769
                    values.clear();
3770
                }
3771
                return me;
3772
            }
3773
3774
            iterator begin() noexcept
3775
            {
3776
                return values.begin();
3777
            }
3778
3779
            const_iterator begin() const noexcept
3780
            {
3781
                return values.begin();
3782
            }
3783
3784
            const_iterator cbegin() const noexcept
3785
            {
3786
                return values.cbegin();
3787
            }
3788
3789
            iterator end() noexcept
3790
            {
3791
                return values.end();
3792
            }
3793
3794
            const_iterator end() const noexcept 
3795
            {
3796
                return values.end();
3797
            }
3798
3799
            const_iterator cend() const noexcept
3800
            {
3801
                return values.cend();
3802
            }
3803
    };
3804
3805
    /** A mapping value flag class
3806
     * 
3807
     * \tparam K the type to extract the argument as
3808
     * \tparam T the type to store the result as
3809
     * \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)
3810
     * \tparam Map The Map type.  Should operate like std::map or std::unordered_map
3811
     */
3812
    template <
3813
        typename K,
3814
        typename T,
3815
        typename Reader = ValueReader,
3816
        template <typename...> class Map = detail::unordered_map>
3817
    class MapFlag : public ValueFlagBase
3818
    {
3819
        private:
3820
            const Map<K, T> map;
3821
            T value;
3822
            const T defaultValue;
3823
            Reader reader;
3824
3825
        protected:
3826
            virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3827
            {
3828
                return detail::MapKeysToStrings(map);
3829
            }
3830
3831
        public:
3832
3833
            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_)
3834
            {
3835
                group_.Add(*this);
3836
            }
3837
3838
            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)
3839
            {
3840
            }
3841
3842
            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_)
3843
            {
3844
            }
3845
3846
            virtual ~MapFlag() {}
3847
3848
            virtual void ParseValue(const std::vector<std::string> &values_) override
3849
            {
3850
                const std::string &value_ = values_.at(0);
3851
3852
                K key;
3853
#ifdef ARGS_NOEXCEPT
3854
                if (!reader(name, value_, key))
3855
                {
3856
                    error = Error::Parse;
3857
                }
3858
#else
3859
                reader(name, value_, key);
3860
#endif
3861
                auto it = map.find(key);
3862
                if (it == std::end(map))
3863
                {
3864
                    std::ostringstream problem;
3865
                    problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3866
#ifdef ARGS_NOEXCEPT
3867
                    error = Error::Map;
3868
                    errorMsg = problem.str();
3869
#else
3870
                    throw MapError(problem.str());
3871
#endif
3872
                } else
3873
                {
3874
                    this->value = it->second;
3875
                }
3876
            }
3877
3878
            /** Get the value
3879
             */
3880
            T &Get() noexcept
3881
            {
3882
                return value;
3883
            }
3884
3885
            /** Get the value
3886
             */
3887
            T &operator *() noexcept
3888
            {
3889
                return value;
3890
            }
3891
3892
            /** Get the value
3893
             */
3894
            const T &operator *() const noexcept
3895
            {
3896
                return value;
3897
            }
3898
3899
            /** Get the value
3900
             */
3901
            T *operator ->() noexcept
3902
            {
3903
                return &value;
3904
            }
3905
3906
            /** Get the value
3907
             */
3908
            const T *operator ->() const noexcept
3909
            {
3910
                return &value;
3911
            }
3912
3913
            virtual void Reset() noexcept override
3914
            {
3915
                ValueFlagBase::Reset();
3916
                value = defaultValue;
3917
            }
3918
    };
3919
3920
    /** A mapping value flag list class
3921
     * 
3922
     * \tparam K the type to extract the argument as
3923
     * \tparam T the type to store the result as
3924
     * \tparam List the list type that houses the values
3925
     * \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)
3926
     * \tparam Map The Map type.  Should operate like std::map or std::unordered_map
3927
     */
3928
    template <
3929
        typename K,
3930
        typename T,
3931
        template <typename...> class List = detail::vector,
3932
        typename Reader = ValueReader,
3933
        template <typename...> class Map = detail::unordered_map>
3934
    class MapFlagList : public ValueFlagBase
3935
    {
3936
        private:
3937
            using Container = List<T>;
3938
            const Map<K, T> map;
3939
            Container values;
3940
            const Container defaultValues;
3941
            Reader reader;
3942
3943
        protected:
3944
            virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
3945
            {
3946
                return detail::MapKeysToStrings(map);
3947
            }
3948
3949
        public:
3950
            typedef T value_type;
3951
            typedef typename Container::allocator_type allocator_type;
3952
            typedef typename Container::pointer pointer;
3953
            typedef typename Container::const_pointer const_pointer;
3954
            typedef T& reference;
3955
            typedef const T& const_reference;
3956
            typedef typename Container::size_type size_type;
3957
            typedef typename Container::difference_type difference_type;
3958
            typedef typename Container::iterator iterator;
3959
            typedef typename Container::const_iterator const_iterator;
3960
            typedef std::reverse_iterator<iterator> reverse_iterator;
3961
            typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3962
3963
            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_)
3964
            {
3965
                group_.Add(*this);
3966
            }
3967
3968
            virtual ~MapFlagList() {}
3969
3970
            virtual void ParseValue(const std::vector<std::string> &values_) override
3971
            {
3972
                const std::string &value = values_.at(0);
3973
3974
                K key;
3975
#ifdef ARGS_NOEXCEPT
3976
                if (!reader(name, value, key))
3977
                {
3978
                    error = Error::Parse;
3979
                }
3980
#else
3981
                reader(name, value, key);
3982
#endif
3983
                auto it = map.find(key);
3984
                if (it == std::end(map))
3985
                {
3986
                    std::ostringstream problem;
3987
                    problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
3988
#ifdef ARGS_NOEXCEPT
3989
                    error = Error::Map;
3990
                    errorMsg = problem.str();
3991
#else
3992
                    throw MapError(problem.str());
3993
#endif
3994
                } else
3995
                {
3996
                    this->values.emplace_back(it->second);
3997
                }
3998
            }
3999
4000
            /** Get the value
4001
             */
4002
            Container &Get() noexcept
4003
            {
4004
                return values;
4005
            }
4006
4007
            /** Get the value
4008
             */
4009
            Container &operator *() noexcept
4010
            {
4011
                return values;
4012
            }
4013
4014
            /** Get the values
4015
             */
4016
            const Container &operator *() const noexcept
4017
            {
4018
                return values;
4019
            }
4020
4021
            /** Get the values
4022
             */
4023
            Container *operator ->() noexcept
4024
            {
4025
                return &values;
4026
            }
4027
4028
            /** Get the values
4029
             */
4030
            const Container *operator ->() const noexcept
4031
            {
4032
                return &values;
4033
            }
4034
4035
            virtual std::string Name() const override
4036
            {
4037
                return name + std::string("...");
4038
            }
4039
4040
            virtual void Reset() noexcept override
4041
            {
4042
                ValueFlagBase::Reset();
4043
                values = defaultValues;
4044
            }
4045
4046
            virtual FlagBase *Match(const EitherFlag &arg) override
4047
            {
4048
                const bool wasMatched = Matched();
4049
                auto me = FlagBase::Match(arg);
4050
                if (me && !wasMatched)
4051
                {
4052
                    values.clear();
4053
                }
4054
                return me;
4055
            }
4056
4057
            iterator begin() noexcept
4058
            {
4059
                return values.begin();
4060
            }
4061
4062
            const_iterator begin() const noexcept
4063
            {
4064
                return values.begin();
4065
            }
4066
4067
            const_iterator cbegin() const noexcept
4068
            {
4069
                return values.cbegin();
4070
            }
4071
4072
            iterator end() noexcept
4073
            {
4074
                return values.end();
4075
            }
4076
4077
            const_iterator end() const noexcept 
4078
            {
4079
                return values.end();
4080
            }
4081
4082
            const_iterator cend() const noexcept
4083
            {
4084
                return values.cend();
4085
            }
4086
    };
4087
4088
    /** A positional argument class
4089
     *
4090
     * \tparam T the type to extract the argument as
4091
     * \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)
4092
     */
4093
    template <
4094
        typename T,
4095
        typename Reader = ValueReader>
4096
    class Positional : public PositionalBase
4097
    {
4098
        private:
4099
            T value;
4100
            const T defaultValue;
4101
            Reader reader;
4102
        public:
4103
            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_)
4104
            {
4105
                group_.Add(*this);
4106
            }
4107
4108
            Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_)
4109
            {
4110
            }
4111
4112
            virtual ~Positional() {}
4113
4114
            virtual void ParseValue(const std::string &value_) override
4115
            {
4116
#ifdef ARGS_NOEXCEPT
4117
                if (!reader(name, value_, this->value))
4118
                {
4119
                    error = Error::Parse;
4120
                }
4121
#else
4122
                reader(name, value_, this->value);
4123
#endif
4124
                ready = false;
4125
                matched = true;
4126
            }
4127
4128
            /** Get the value
4129
             */
4130
            T &Get() noexcept
4131
            {
4132
                return value;
4133
            }
4134
4135
            /** Get the value
4136
             */
4137
            T &operator *() noexcept
4138
            {
4139
                return value;
4140
            }
4141
4142
            /** Get the value
4143
             */
4144
            const T &operator *() const noexcept
4145
            {
4146
                return value;
4147
            }
4148
4149
            /** Get the value
4150
             */
4151
            T *operator ->() noexcept
4152
            {
4153
                return &value;
4154
            }
4155
4156
            /** Get the value
4157
             */
4158
            const T *operator ->() const noexcept
4159
            {
4160
                return &value;
4161
            }
4162
4163
            virtual void Reset() noexcept override
4164
            {
4165
                PositionalBase::Reset();
4166
                value = defaultValue;
4167
            }
4168
    };
4169
4170
    /** A positional argument class that pushes the found values into a list
4171
     * 
4172
     * \tparam T the type to extract the argument as
4173
     * \tparam List the list type that houses the values
4174
     * \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)
4175
     */
4176
    template <
4177
        typename T,
4178
        template <typename...> class List = detail::vector,
4179
        typename Reader = ValueReader>
4180
    class PositionalList : public PositionalBase
4181
    {
4182
        private:
4183
            using Container = List<T>;
4184
            Container values;
4185
            const Container defaultValues;
4186
            Reader reader;
4187
4188
        public:
4189
            typedef T value_type;
4190
            typedef typename Container::allocator_type allocator_type;
4191
            typedef typename Container::pointer pointer;
4192
            typedef typename Container::const_pointer const_pointer;
4193
            typedef T& reference;
4194
            typedef const T& const_reference;
4195
            typedef typename Container::size_type size_type;
4196
            typedef typename Container::difference_type difference_type;
4197
            typedef typename Container::iterator iterator;
4198
            typedef typename Container::const_iterator const_iterator;
4199
            typedef std::reverse_iterator<iterator> reverse_iterator;
4200
            typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4201
4202
            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_)
4203
            {
4204
                group_.Add(*this);
4205
            }
4206
4207
            PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_)
4208
            {
4209
            }
4210
4211
            virtual ~PositionalList() {}
4212
4213
            virtual void ParseValue(const std::string &value_) override
4214
            {
4215
                T v;
4216
#ifdef ARGS_NOEXCEPT
4217
                if (!reader(name, value_, v))
4218
                {
4219
                    error = Error::Parse;
4220
                }
4221
#else
4222
                reader(name, value_, v);
4223
#endif
4224
                values.insert(std::end(values), v);
4225
                matched = true;
4226
            }
4227
4228
            virtual std::string Name() const override
4229
            {
4230
                return name + std::string("...");
4231
            }
4232
4233
            /** Get the values
4234
             */
4235
            Container &Get() noexcept
4236
            {
4237
                return values;
4238
            }
4239
4240
            /** Get the value
4241
             */
4242
            Container &operator *() noexcept
4243
            {
4244
                return values;
4245
            }
4246
4247
            /** Get the values
4248
             */
4249
            const Container &operator *() const noexcept
4250
            {
4251
                return values;
4252
            }
4253
4254
            /** Get the values
4255
             */
4256
            Container *operator ->() noexcept
4257
            {
4258
                return &values;
4259
            }
4260
4261
            /** Get the values
4262
             */
4263
            const Container *operator ->() const noexcept
4264
            {
4265
                return &values;
4266
            }
4267
4268
            virtual void Reset() noexcept override
4269
            {
4270
                PositionalBase::Reset();
4271
                values = defaultValues;
4272
            }
4273
4274
            virtual PositionalBase *GetNextPositional() override
4275
            {
4276
                const bool wasMatched = Matched();
4277
                auto me = PositionalBase::GetNextPositional();
4278
                if (me && !wasMatched)
4279
                {
4280
                    values.clear();
4281
                }
4282
                return me;
4283
            }
4284
4285
            iterator begin() noexcept
4286
            {
4287
                return values.begin();
4288
            }
4289
4290
            const_iterator begin() const noexcept
4291
            {
4292
                return values.begin();
4293
            }
4294
4295
            const_iterator cbegin() const noexcept
4296
            {
4297
                return values.cbegin();
4298
            }
4299
4300
            iterator end() noexcept
4301
            {
4302
                return values.end();
4303
            }
4304
4305
            const_iterator end() const noexcept 
4306
            {
4307
                return values.end();
4308
            }
4309
4310
            const_iterator cend() const noexcept
4311
            {
4312
                return values.cend();
4313
            }
4314
    };
4315
4316
    /** A positional argument mapping class
4317
     * 
4318
     * \tparam K the type to extract the argument as
4319
     * \tparam T the type to store the result as
4320
     * \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)
4321
     * \tparam Map The Map type.  Should operate like std::map or std::unordered_map
4322
     */
4323
    template <
4324
        typename K,
4325
        typename T,
4326
        typename Reader = ValueReader,
4327
        template <typename...> class Map = detail::unordered_map>
4328
    class MapPositional : public PositionalBase
4329
    {
4330
        private:
4331
            const Map<K, T> map;
4332
            T value;
4333
            const T defaultValue;
4334
            Reader reader;
4335
4336
        protected:
4337
            virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4338
            {
4339
                return detail::MapKeysToStrings(map);
4340
            }
4341
4342
        public:
4343
4344
            MapPositional(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const T &defaultValue_ = T(), Options options_ = {}):
4345
                PositionalBase(name_, help_, options_), map(map_), value(defaultValue_), defaultValue(defaultValue_)
4346
            {
4347
                group_.Add(*this);
4348
            }
4349
4350
            virtual ~MapPositional() {}
4351
4352
            virtual void ParseValue(const std::string &value_) override
4353
            {
4354
                K key;
4355
#ifdef ARGS_NOEXCEPT
4356
                if (!reader(name, value_, key))
4357
                {
4358
                    error = Error::Parse;
4359
                }
4360
#else
4361
                reader(name, value_, key);
4362
#endif
4363
                auto it = map.find(key);
4364
                if (it == std::end(map))
4365
                {
4366
                    std::ostringstream problem;
4367
                    problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4368
#ifdef ARGS_NOEXCEPT
4369
                    error = Error::Map;
4370
                    errorMsg = problem.str();
4371
#else
4372
                    throw MapError(problem.str());
4373
#endif
4374
                } else
4375
                {
4376
                    this->value = it->second;
4377
                    ready = false;
4378
                    matched = true;
4379
                }
4380
            }
4381
4382
            /** Get the value
4383
             */
4384
            T &Get() noexcept
4385
            {
4386
                return value;
4387
            }
4388
4389
            /** Get the value
4390
             */
4391
            T &operator *() noexcept
4392
            {
4393
                return value;
4394
            }
4395
4396
            /** Get the value
4397
             */
4398
            const T &operator *() const noexcept
4399
            {
4400
                return value;
4401
            }
4402
4403
            /** Get the value
4404
             */
4405
            T *operator ->() noexcept
4406
            {
4407
                return &value;
4408
            }
4409
4410
            /** Get the value
4411
             */
4412
            const T *operator ->() const noexcept
4413
            {
4414
                return &value;
4415
            }
4416
4417
            virtual void Reset() noexcept override
4418
            {
4419
                PositionalBase::Reset();
4420
                value = defaultValue;
4421
            }
4422
    };
4423
4424
    /** A positional argument mapping list class
4425
     * 
4426
     * \tparam K the type to extract the argument as
4427
     * \tparam T the type to store the result as
4428
     * \tparam List the list type that houses the values
4429
     * \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)
4430
     * \tparam Map The Map type.  Should operate like std::map or std::unordered_map
4431
     */
4432
    template <
4433
        typename K,
4434
        typename T,
4435
        template <typename...> class List = detail::vector,
4436
        typename Reader = ValueReader,
4437
        template <typename...> class Map = detail::unordered_map>
4438
    class MapPositionalList : public PositionalBase
4439
    {
4440
        private:
4441
            using Container = List<T>;
4442
4443
            const Map<K, T> map;
4444
            Container values;
4445
            const Container defaultValues;
4446
            Reader reader;
4447
4448
        protected:
4449
            virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
4450
            {
4451
                return detail::MapKeysToStrings(map);
4452
            }
4453
4454
        public:
4455
            typedef T value_type;
4456
            typedef typename Container::allocator_type allocator_type;
4457
            typedef typename Container::pointer pointer;
4458
            typedef typename Container::const_pointer const_pointer;
4459
            typedef T& reference;
4460
            typedef const T& const_reference;
4461
            typedef typename Container::size_type size_type;
4462
            typedef typename Container::difference_type difference_type;
4463
            typedef typename Container::iterator iterator;
4464
            typedef typename Container::const_iterator const_iterator;
4465
            typedef std::reverse_iterator<iterator> reverse_iterator;
4466
            typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4467
4468
            MapPositionalList(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const Container &defaultValues_ = Container(), Options options_ = {}):
4469
                PositionalBase(name_, help_, options_), map(map_), values(defaultValues_), defaultValues(defaultValues_)
4470
            {
4471
                group_.Add(*this);
4472
            }
4473
4474
            virtual ~MapPositionalList() {}
4475
4476
            virtual void ParseValue(const std::string &value_) override
4477
            {
4478
                K key;
4479
#ifdef ARGS_NOEXCEPT
4480
                if (!reader(name, value_, key))
4481
                {
4482
                    error = Error::Parse;
4483
                }
4484
#else
4485
                reader(name, value_, key);
4486
#endif
4487
                auto it = map.find(key);
4488
                if (it == std::end(map))
4489
                {
4490
                    std::ostringstream problem;
4491
                    problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
4492
#ifdef ARGS_NOEXCEPT
4493
                    error = Error::Map;
4494
                    errorMsg = problem.str();
4495
#else
4496
                    throw MapError(problem.str());
4497
#endif
4498
                } else
4499
                {
4500
                    this->values.emplace_back(it->second);
4501
                    matched = true;
4502
                }
4503
            }
4504
4505
            /** Get the value
4506
             */
4507
            Container &Get() noexcept
4508
            {
4509
                return values;
4510
            }
4511
4512
            /** Get the value
4513
             */
4514
            Container &operator *() noexcept
4515
            {
4516
                return values;
4517
            }
4518
4519
            /** Get the values
4520
             */
4521
            const Container &operator *() const noexcept
4522
            {
4523
                return values;
4524
            }
4525
4526
            /** Get the values
4527
             */
4528
            Container *operator ->() noexcept
4529
            {
4530
                return &values;
4531
            }
4532
4533
            /** Get the values
4534
             */
4535
            const Container *operator ->() const noexcept
4536
            {
4537
                return &values;
4538
            }
4539
4540
            virtual std::string Name() const override
4541
            {
4542
                return name + std::string("...");
4543
            }
4544
4545
            virtual void Reset() noexcept override
4546
            {
4547
                PositionalBase::Reset();
4548
                values = defaultValues;
4549
            }
4550
4551
            virtual PositionalBase *GetNextPositional() override
4552
            {
4553
                const bool wasMatched = Matched();
4554
                auto me = PositionalBase::GetNextPositional();
4555
                if (me && !wasMatched)
4556
                {
4557
                    values.clear();
4558
                }
4559
                return me;
4560
            }
4561
4562
            iterator begin() noexcept
4563
            {
4564
                return values.begin();
4565
            }
4566
4567
            const_iterator begin() const noexcept
4568
            {
4569
                return values.begin();
4570
            }
4571
4572
            const_iterator cbegin() const noexcept
4573
            {
4574
                return values.cbegin();
4575
            }
4576
4577
            iterator end() noexcept
4578
            {
4579
                return values.end();
4580
            }
4581
4582
            const_iterator end() const noexcept 
4583
            {
4584
                return values.end();
4585
            }
4586
4587
            const_iterator cend() const noexcept
4588
            {
4589
                return values.cend();
4590
            }
4591
    };
4592
}
4593
4594
#endif