You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4284 lines
142KB

  1. /* A simple header-only C++ argument parser library.
  2. *
  3. * https://github.com/Taywee/args
  4. *
  5. * Copyright (c) 2016-2019 Taylor C. Richberger <taywee@gmx.com> and Pavel
  6. * Belikov
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to
  10. * deal in the Software without restriction, including without limitation the
  11. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  12. * sell copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  24. * IN THE SOFTWARE.
  25. */
  26. /** \file args.hxx
  27. * \brief this single-header lets you use all of the args functionality
  28. *
  29. * The important stuff is done inside the args namespace
  30. */
  31. #ifndef ARGS_HXX
  32. #define ARGS_HXX
  33. #include <algorithm>
  34. #include <iterator>
  35. #include <exception>
  36. #include <functional>
  37. #include <sstream>
  38. #include <string>
  39. #include <tuple>
  40. #include <vector>
  41. #include <unordered_map>
  42. #include <unordered_set>
  43. #include <type_traits>
  44. #include <cstddef>
  45. #ifdef ARGS_TESTNAMESPACE
  46. namespace argstest
  47. {
  48. #else
  49. /** \namespace args
  50. * \brief contains all the functionality of the args library
  51. */
  52. namespace args
  53. {
  54. #endif
  55. /** Getter to grab the value from the argument type.
  56. *
  57. * If the Get() function of the type returns a reference, so does this, and
  58. * the value will be modifiable.
  59. */
  60. template <typename Option>
  61. auto get(Option &option_) -> decltype(option_.Get())
  62. {
  63. return option_.Get();
  64. }
  65. /** (INTERNAL) Count UTF-8 glyphs
  66. *
  67. * This is not reliable, and will fail for combinatory glyphs, but it's
  68. * good enough here for now.
  69. *
  70. * \param string The string to count glyphs from
  71. * \return The UTF-8 glyphs in the string
  72. */
  73. inline std::string::size_type Glyphs(const std::string &string_)
  74. {
  75. std::string::size_type length = 0;
  76. for (const char c: string_)
  77. {
  78. if ((c & 0xc0) != 0x80)
  79. {
  80. ++length;
  81. }
  82. }
  83. return length;
  84. }
  85. /** (INTERNAL) Wrap a vector of words into a vector of lines
  86. *
  87. * Empty words are skipped. Word "\n" forces wrapping.
  88. *
  89. * \param begin The begin iterator
  90. * \param end The end iterator
  91. * \param width The width of the body
  92. * \param firstlinewidth the width of the first line, defaults to the width of the body
  93. * \param firstlineindent the indent of the first line, defaults to 0
  94. * \return the vector of lines
  95. */
  96. template <typename It>
  97. inline std::vector<std::string> Wrap(It begin,
  98. It end,
  99. const std::string::size_type width,
  100. std::string::size_type firstlinewidth = 0,
  101. std::string::size_type firstlineindent = 0)
  102. {
  103. std::vector<std::string> output;
  104. std::string line(firstlineindent, ' ');
  105. bool empty = true;
  106. if (firstlinewidth == 0)
  107. {
  108. firstlinewidth = width;
  109. }
  110. auto currentwidth = firstlinewidth;
  111. for (auto it = begin; it != end; ++it)
  112. {
  113. if (it->empty())
  114. {
  115. continue;
  116. }
  117. if (*it == "\n")
  118. {
  119. if (!empty)
  120. {
  121. output.push_back(line);
  122. line.clear();
  123. empty = true;
  124. currentwidth = width;
  125. }
  126. continue;
  127. }
  128. auto itemsize = Glyphs(*it);
  129. if ((line.length() + 1 + itemsize) > currentwidth)
  130. {
  131. if (!empty)
  132. {
  133. output.push_back(line);
  134. line.clear();
  135. empty = true;
  136. currentwidth = width;
  137. }
  138. }
  139. if (itemsize > 0)
  140. {
  141. if (!empty)
  142. {
  143. line += ' ';
  144. }
  145. line += *it;
  146. empty = false;
  147. }
  148. }
  149. if (!empty)
  150. {
  151. output.push_back(line);
  152. }
  153. return output;
  154. }
  155. namespace detail
  156. {
  157. template <typename T>
  158. std::string Join(const T& array, const std::string &delimiter)
  159. {
  160. std::string res;
  161. for (auto &element : array)
  162. {
  163. if (!res.empty())
  164. {
  165. res += delimiter;
  166. }
  167. res += element;
  168. }
  169. return res;
  170. }
  171. }
  172. /** (INTERNAL) Wrap a string into a vector of lines
  173. *
  174. * This is quick and hacky, but works well enough. You can specify a
  175. * different width for the first line
  176. *
  177. * \param width The width of the body
  178. * \param firstlinewid the width of the first line, defaults to the width of the body
  179. * \return the vector of lines
  180. */
  181. inline std::vector<std::string> Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0)
  182. {
  183. // Preserve existing line breaks
  184. const auto newlineloc = in.find('\n');
  185. if (newlineloc != in.npos)
  186. {
  187. auto first = Wrap(std::string(in, 0, newlineloc), width);
  188. auto second = Wrap(std::string(in, newlineloc + 1), width);
  189. first.insert(
  190. std::end(first),
  191. std::make_move_iterator(std::begin(second)),
  192. std::make_move_iterator(std::end(second)));
  193. return first;
  194. }
  195. std::istringstream stream(in);
  196. std::string::size_type indent = 0;
  197. for (char c : in)
  198. {
  199. if (!isspace(c))
  200. {
  201. break;
  202. }
  203. ++indent;
  204. }
  205. return Wrap(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>(),
  206. width, firstlinewidth, indent);
  207. }
  208. #ifdef ARGS_NOEXCEPT
  209. /// Error class, for when ARGS_NOEXCEPT is defined
  210. enum class Error
  211. {
  212. None,
  213. Usage,
  214. Parse,
  215. Validation,
  216. Required,
  217. Map,
  218. Extra,
  219. Help,
  220. Subparser,
  221. Completion,
  222. };
  223. #else
  224. /** Base error class
  225. */
  226. class Error : public std::runtime_error
  227. {
  228. public:
  229. Error(const std::string &problem) : std::runtime_error(problem) {}
  230. virtual ~Error() {}
  231. };
  232. /** Errors that occur during usage
  233. */
  234. class UsageError : public Error
  235. {
  236. public:
  237. UsageError(const std::string &problem) : Error(problem) {}
  238. virtual ~UsageError() {}
  239. };
  240. /** Errors that occur during regular parsing
  241. */
  242. class ParseError : public Error
  243. {
  244. public:
  245. ParseError(const std::string &problem) : Error(problem) {}
  246. virtual ~ParseError() {}
  247. };
  248. /** Errors that are detected from group validation after parsing finishes
  249. */
  250. class ValidationError : public Error
  251. {
  252. public:
  253. ValidationError(const std::string &problem) : Error(problem) {}
  254. virtual ~ValidationError() {}
  255. };
  256. /** Errors that when a required flag is omitted
  257. */
  258. class RequiredError : public ValidationError
  259. {
  260. public:
  261. RequiredError(const std::string &problem) : ValidationError(problem) {}
  262. virtual ~RequiredError() {}
  263. };
  264. /** Errors in map lookups
  265. */
  266. class MapError : public ParseError
  267. {
  268. public:
  269. MapError(const std::string &problem) : ParseError(problem) {}
  270. virtual ~MapError() {}
  271. };
  272. /** Error that occurs when a singular flag is specified multiple times
  273. */
  274. class ExtraError : public ParseError
  275. {
  276. public:
  277. ExtraError(const std::string &problem) : ParseError(problem) {}
  278. virtual ~ExtraError() {}
  279. };
  280. /** An exception that indicates that the user has requested help
  281. */
  282. class Help : public Error
  283. {
  284. public:
  285. Help(const std::string &flag) : Error(flag) {}
  286. virtual ~Help() {}
  287. };
  288. /** (INTERNAL) An exception that emulates coroutine-like control flow for subparsers.
  289. */
  290. class SubparserError : public Error
  291. {
  292. public:
  293. SubparserError() : Error("") {}
  294. virtual ~SubparserError() {}
  295. };
  296. /** An exception that contains autocompletion reply
  297. */
  298. class Completion : public Error
  299. {
  300. public:
  301. Completion(const std::string &flag) : Error(flag) {}
  302. virtual ~Completion() {}
  303. };
  304. #endif
  305. /** A simple unified option type for unified initializer lists for the Matcher class.
  306. */
  307. struct EitherFlag
  308. {
  309. const bool isShort;
  310. const char shortFlag;
  311. const std::string longFlag;
  312. EitherFlag(const std::string &flag) : isShort(false), shortFlag(), longFlag(flag) {}
  313. EitherFlag(const char *flag) : isShort(false), shortFlag(), longFlag(flag) {}
  314. EitherFlag(const char flag) : isShort(true), shortFlag(flag), longFlag() {}
  315. /** Get just the long flags from an initializer list of EitherFlags
  316. */
  317. static std::unordered_set<std::string> GetLong(std::initializer_list<EitherFlag> flags)
  318. {
  319. std::unordered_set<std::string> longFlags;
  320. for (const EitherFlag &flag: flags)
  321. {
  322. if (!flag.isShort)
  323. {
  324. longFlags.insert(flag.longFlag);
  325. }
  326. }
  327. return longFlags;
  328. }
  329. /** Get just the short flags from an initializer list of EitherFlags
  330. */
  331. static std::unordered_set<char> GetShort(std::initializer_list<EitherFlag> flags)
  332. {
  333. std::unordered_set<char> shortFlags;
  334. for (const EitherFlag &flag: flags)
  335. {
  336. if (flag.isShort)
  337. {
  338. shortFlags.insert(flag.shortFlag);
  339. }
  340. }
  341. return shortFlags;
  342. }
  343. std::string str() const
  344. {
  345. return isShort ? std::string(1, shortFlag) : longFlag;
  346. }
  347. std::string str(const std::string &shortPrefix, const std::string &longPrefix) const
  348. {
  349. return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag;
  350. }
  351. };
  352. /** A class of "matchers", specifying short and flags that can possibly be
  353. * matched.
  354. *
  355. * This is supposed to be constructed and then passed in, not used directly
  356. * from user code.
  357. */
  358. class Matcher
  359. {
  360. private:
  361. const std::unordered_set<char> shortFlags;
  362. const std::unordered_set<std::string> longFlags;
  363. public:
  364. /** Specify short and long flags separately as iterators
  365. *
  366. * ex: `args::Matcher(shortFlags.begin(), shortFlags.end(), longFlags.begin(), longFlags.end())`
  367. */
  368. template <typename ShortIt, typename LongIt>
  369. Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd) :
  370. shortFlags(shortFlagsStart, shortFlagsEnd),
  371. longFlags(longFlagsStart, longFlagsEnd)
  372. {
  373. if (shortFlags.empty() && longFlags.empty())
  374. {
  375. #ifndef ARGS_NOEXCEPT
  376. throw UsageError("empty Matcher");
  377. #endif
  378. }
  379. }
  380. #ifdef ARGS_NOEXCEPT
  381. /// Only for ARGS_NOEXCEPT
  382. Error GetError() const noexcept
  383. {
  384. return shortFlags.empty() && longFlags.empty() ? Error::Usage : Error::None;
  385. }
  386. #endif
  387. /** Specify short and long flags separately as iterables
  388. *
  389. * ex: `args::Matcher(shortFlags, longFlags)`
  390. */
  391. template <typename Short, typename Long>
  392. Matcher(Short &&shortIn, Long &&longIn) :
  393. Matcher(std::begin(shortIn), std::end(shortIn), std::begin(longIn), std::end(longIn))
  394. {}
  395. /** Specify a mixed single initializer-list of both short and long flags
  396. *
  397. * This is the fancy one. It takes a single initializer list of
  398. * any number of any mixed kinds of flags. Chars are
  399. * automatically interpreted as short flags, and strings are
  400. * automatically interpreted as long flags:
  401. *
  402. * args::Matcher{'a'}
  403. * args::Matcher{"foo"}
  404. * args::Matcher{'h', "help"}
  405. * args::Matcher{"foo", 'f', 'F', "FoO"}
  406. */
  407. Matcher(std::initializer_list<EitherFlag> in) :
  408. Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {}
  409. Matcher(Matcher &&other) : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags))
  410. {}
  411. ~Matcher() {}
  412. /** (INTERNAL) Check if there is a match of a short flag
  413. */
  414. bool Match(const char flag) const
  415. {
  416. return shortFlags.find(flag) != shortFlags.end();
  417. }
  418. /** (INTERNAL) Check if there is a match of a long flag
  419. */
  420. bool Match(const std::string &flag) const
  421. {
  422. return longFlags.find(flag) != longFlags.end();
  423. }
  424. /** (INTERNAL) Check if there is a match of a flag
  425. */
  426. bool Match(const EitherFlag &flag) const
  427. {
  428. return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag);
  429. }
  430. /** (INTERNAL) Get all flag strings as a vector, with the prefixes embedded
  431. */
  432. std::vector<EitherFlag> GetFlagStrings() const
  433. {
  434. std::vector<EitherFlag> flagStrings;
  435. flagStrings.reserve(shortFlags.size() + longFlags.size());
  436. for (const char flag: shortFlags)
  437. {
  438. flagStrings.emplace_back(flag);
  439. }
  440. for (const std::string &flag: longFlags)
  441. {
  442. flagStrings.emplace_back(flag);
  443. }
  444. return flagStrings;
  445. }
  446. /** (INTERNAL) Get long flag if it exists or any short flag
  447. */
  448. EitherFlag GetLongOrAny() const
  449. {
  450. if (!longFlags.empty())
  451. {
  452. return *longFlags.begin();
  453. }
  454. if (!shortFlags.empty())
  455. {
  456. return *shortFlags.begin();
  457. }
  458. // should be unreachable
  459. return ' ';
  460. }
  461. /** (INTERNAL) Get short flag if it exists or any long flag
  462. */
  463. EitherFlag GetShortOrAny() const
  464. {
  465. if (!shortFlags.empty())
  466. {
  467. return *shortFlags.begin();
  468. }
  469. if (!longFlags.empty())
  470. {
  471. return *longFlags.begin();
  472. }
  473. // should be unreachable
  474. return ' ';
  475. }
  476. };
  477. /** Attributes for flags.
  478. */
  479. enum class Options
  480. {
  481. /** Default options.
  482. */
  483. None = 0x0,
  484. /** Flag can't be passed multiple times.
  485. */
  486. Single = 0x01,
  487. /** Flag can't be omitted.
  488. */
  489. Required = 0x02,
  490. /** Flag is excluded from usage line.
  491. */
  492. HiddenFromUsage = 0x04,
  493. /** Flag is excluded from options help.
  494. */
  495. HiddenFromDescription = 0x08,
  496. /** Flag is global and can be used in any subcommand.
  497. */
  498. Global = 0x10,
  499. /** Flag stops a parser.
  500. */
  501. KickOut = 0x20,
  502. /** Flag is excluded from auto completion.
  503. */
  504. HiddenFromCompletion = 0x40,
  505. /** Flag is excluded from options help and usage line
  506. */
  507. Hidden = HiddenFromUsage | HiddenFromDescription | HiddenFromCompletion,
  508. };
  509. inline Options operator | (Options lhs, Options rhs)
  510. {
  511. return static_cast<Options>(static_cast<int>(lhs) | static_cast<int>(rhs));
  512. }
  513. inline Options operator & (Options lhs, Options rhs)
  514. {
  515. return static_cast<Options>(static_cast<int>(lhs) & static_cast<int>(rhs));
  516. }
  517. class FlagBase;
  518. class PositionalBase;
  519. class Command;
  520. class ArgumentParser;
  521. /** A simple structure of parameters for easy user-modifyable help menus
  522. */
  523. struct HelpParams
  524. {
  525. /** The width of the help menu
  526. */
  527. unsigned int width = 80;
  528. /** The indent of the program line
  529. */
  530. unsigned int progindent = 2;
  531. /** The indent of the program trailing lines for long parameters
  532. */
  533. unsigned int progtailindent = 4;
  534. /** The indent of the description and epilogs
  535. */
  536. unsigned int descriptionindent = 4;
  537. /** The indent of the flags
  538. */
  539. unsigned int flagindent = 6;
  540. /** The indent of the flag descriptions
  541. */
  542. unsigned int helpindent = 40;
  543. /** The additional indent each group adds
  544. */
  545. unsigned int eachgroupindent = 2;
  546. /** The minimum gutter between each flag and its help
  547. */
  548. unsigned int gutter = 1;
  549. /** Show the terminator when both options and positional parameters are present
  550. */
  551. bool showTerminator = true;
  552. /** Show the {OPTIONS} on the prog line when this is true
  553. */
  554. bool showProglineOptions = true;
  555. /** Show the positionals on the prog line when this is true
  556. */
  557. bool showProglinePositionals = true;
  558. /** The prefix for short flags
  559. */
  560. std::string shortPrefix;
  561. /** The prefix for long flags
  562. */
  563. std::string longPrefix;
  564. /** The separator for short flags
  565. */
  566. std::string shortSeparator;
  567. /** The separator for long flags
  568. */
  569. std::string longSeparator;
  570. /** The program name for help generation
  571. */
  572. std::string programName;
  573. /** Show command's flags
  574. */
  575. bool showCommandChildren = false;
  576. /** Show command's descriptions and epilog
  577. */
  578. bool showCommandFullHelp = false;
  579. /** The postfix for progline when showProglineOptions is true and command has any flags
  580. */
  581. std::string proglineOptions = "{OPTIONS}";
  582. /** The prefix for progline when command has any subcommands
  583. */
  584. std::string proglineCommand = "COMMAND";
  585. /** The prefix for progline value
  586. */
  587. std::string proglineValueOpen = " <";
  588. /** The postfix for progline value
  589. */
  590. std::string proglineValueClose = ">";
  591. /** The prefix for progline required argument
  592. */
  593. std::string proglineRequiredOpen = "";
  594. /** The postfix for progline required argument
  595. */
  596. std::string proglineRequiredClose = "";
  597. /** The prefix for progline non-required argument
  598. */
  599. std::string proglineNonrequiredOpen = "[";
  600. /** The postfix for progline non-required argument
  601. */
  602. std::string proglineNonrequiredClose = "]";
  603. /** Show flags in program line
  604. */
  605. bool proglineShowFlags = false;
  606. /** Use short flags in program lines when possible
  607. */
  608. bool proglinePreferShortFlags = false;
  609. /** Program line prefix
  610. */
  611. std::string usageString;
  612. /** String shown in help before flags descriptions
  613. */
  614. std::string optionsString = "OPTIONS:";
  615. /** Display value name after all the long and short flags
  616. */
  617. bool useValueNameOnce = false;
  618. /** Show value name
  619. */
  620. bool showValueName = true;
  621. /** Add newline before flag description
  622. */
  623. bool addNewlineBeforeDescription = false;
  624. /** The prefix for option value
  625. */
  626. std::string valueOpen = "[";
  627. /** The postfix for option value
  628. */
  629. std::string valueClose = "]";
  630. /** Add choices to argument description
  631. */
  632. bool addChoices = false;
  633. /** The prefix for choices
  634. */
  635. std::string choiceString = "\nOne of: ";
  636. /** Add default values to argument description
  637. */
  638. bool addDefault = false;
  639. /** The prefix for default values
  640. */
  641. std::string defaultString = "\nDefault: ";
  642. };
  643. /** A number of arguments which can be consumed by an option.
  644. *
  645. * Represents a closed interval [min, max].
  646. */
  647. struct Nargs
  648. {
  649. const size_t min;
  650. const size_t max;
  651. Nargs(size_t min_, size_t max_) : min{min_}, max{max_}
  652. {
  653. #ifndef ARGS_NOEXCEPT
  654. if (max < min)
  655. {
  656. throw UsageError("Nargs: max > min");
  657. }
  658. #endif
  659. }
  660. Nargs(size_t num_) : min{num_}, max{num_}
  661. {
  662. }
  663. friend bool operator == (const Nargs &lhs, const Nargs &rhs)
  664. {
  665. return lhs.min == rhs.min && lhs.max == rhs.max;
  666. }
  667. friend bool operator != (const Nargs &lhs, const Nargs &rhs)
  668. {
  669. return !(lhs == rhs);
  670. }
  671. };
  672. /** Base class for all match types
  673. */
  674. class Base
  675. {
  676. private:
  677. Options options = {};
  678. protected:
  679. bool matched = false;
  680. const std::string help;
  681. #ifdef ARGS_NOEXCEPT
  682. /// Only for ARGS_NOEXCEPT
  683. mutable Error error = Error::None;
  684. mutable std::string errorMsg;
  685. #endif
  686. public:
  687. Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {}
  688. virtual ~Base() {}
  689. Options GetOptions() const noexcept
  690. {
  691. return options;
  692. }
  693. bool IsRequired() const noexcept
  694. {
  695. return (GetOptions() & Options::Required) != Options::None;
  696. }
  697. virtual bool Matched() const noexcept
  698. {
  699. return matched;
  700. }
  701. virtual void Validate(const std::string &, const std::string &) const
  702. {
  703. }
  704. operator bool() const noexcept
  705. {
  706. return Matched();
  707. }
  708. virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &, const unsigned indentLevel) const
  709. {
  710. std::tuple<std::string, std::string, unsigned> description;
  711. std::get<1>(description) = help;
  712. std::get<2>(description) = indentLevel;
  713. return { std::move(description) };
  714. }
  715. virtual std::vector<Command*> GetCommands()
  716. {
  717. return {};
  718. }
  719. virtual bool IsGroup() const
  720. {
  721. return false;
  722. }
  723. virtual FlagBase *Match(const EitherFlag &)
  724. {
  725. return nullptr;
  726. }
  727. virtual PositionalBase *GetNextPositional()
  728. {
  729. return nullptr;
  730. }
  731. virtual std::vector<FlagBase*> GetAllFlags()
  732. {
  733. return {};
  734. }
  735. virtual bool HasFlag() const
  736. {
  737. return false;
  738. }
  739. virtual bool HasPositional() const
  740. {
  741. return false;
  742. }
  743. virtual bool HasCommand() const
  744. {
  745. return false;
  746. }
  747. virtual std::vector<std::string> GetProgramLine(const HelpParams &) const
  748. {
  749. return {};
  750. }
  751. /// Sets a kick-out value for building subparsers
  752. void KickOut(bool kickout_) noexcept
  753. {
  754. if (kickout_)
  755. {
  756. options = options | Options::KickOut;
  757. }
  758. else
  759. {
  760. options = static_cast<Options>(static_cast<int>(options) & ~static_cast<int>(Options::KickOut));
  761. }
  762. }
  763. /// Gets the kick-out value for building subparsers
  764. bool KickOut() const noexcept
  765. {
  766. return (options & Options::KickOut) != Options::None;
  767. }
  768. virtual void Reset() noexcept
  769. {
  770. matched = false;
  771. #ifdef ARGS_NOEXCEPT
  772. error = Error::None;
  773. errorMsg.clear();
  774. #endif
  775. }
  776. #ifdef ARGS_NOEXCEPT
  777. /// Only for ARGS_NOEXCEPT
  778. virtual Error GetError() const
  779. {
  780. return error;
  781. }
  782. /// Only for ARGS_NOEXCEPT
  783. std::string GetErrorMsg() const
  784. {
  785. return errorMsg;
  786. }
  787. #endif
  788. };
  789. /** Base class for all match types that have a name
  790. */
  791. class NamedBase : public Base
  792. {
  793. protected:
  794. const std::string name;
  795. bool kickout = false;
  796. std::string defaultString;
  797. bool defaultStringManual = false;
  798. std::vector<std::string> choicesStrings;
  799. bool choicesStringManual = false;
  800. virtual std::string GetDefaultString(const HelpParams&) const { return {}; }
  801. virtual std::vector<std::string> GetChoicesStrings(const HelpParams&) const { return {}; }
  802. virtual std::string GetNameString(const HelpParams&) const { return Name(); }
  803. void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const
  804. {
  805. if (isManual && !manual.empty())
  806. {
  807. dest += str;
  808. dest += manual;
  809. }
  810. else if (!isManual && isGenerated && !generated.empty())
  811. {
  812. dest += str;
  813. dest += generated;
  814. }
  815. }
  816. public:
  817. NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {}
  818. virtual ~NamedBase() {}
  819. /** Sets default value string that will be added to argument description.
  820. * Use empty string to disable it for this argument.
  821. */
  822. void HelpDefault(const std::string &str)
  823. {
  824. defaultStringManual = true;
  825. defaultString = str;
  826. }
  827. /** Gets default value string that will be added to argument description.
  828. */
  829. std::string HelpDefault(const HelpParams &params) const
  830. {
  831. return defaultStringManual ? defaultString : GetDefaultString(params);
  832. }
  833. /** Sets choices strings that will be added to argument description.
  834. * Use empty vector to disable it for this argument.
  835. */
  836. void HelpChoices(const std::vector<std::string> &array)
  837. {
  838. choicesStringManual = true;
  839. choicesStrings = array;
  840. }
  841. /** Gets choices strings that will be added to argument description.
  842. */
  843. std::vector<std::string> HelpChoices(const HelpParams &params) const
  844. {
  845. return choicesStringManual ? choicesStrings : GetChoicesStrings(params);
  846. }
  847. virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned indentLevel) const override
  848. {
  849. std::tuple<std::string, std::string, unsigned> description;
  850. std::get<0>(description) = GetNameString(params);
  851. std::get<1>(description) = help;
  852. std::get<2>(description) = indentLevel;
  853. AddDescriptionPostfix(std::get<1>(description), choicesStringManual, detail::Join(choicesStrings, ", "), params.addChoices, detail::Join(GetChoicesStrings(params), ", "), params.choiceString);
  854. AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString);
  855. return { std::move(description) };
  856. }
  857. virtual std::string Name() const
  858. {
  859. return name;
  860. }
  861. };
  862. namespace detail
  863. {
  864. template <typename T, typename = int>
  865. struct IsConvertableToString : std::false_type {};
  866. template <typename T>
  867. struct IsConvertableToString<T, decltype(std::declval<std::ostringstream&>() << std::declval<T>(), int())> : std::true_type {};
  868. template <typename T>
  869. typename std::enable_if<IsConvertableToString<T>::value, std::string>::type
  870. ToString(const T &value)
  871. {
  872. std::ostringstream s;
  873. s << value;
  874. return s.str();
  875. }
  876. template <typename T>
  877. typename std::enable_if<!IsConvertableToString<T>::value, std::string>::type
  878. ToString(const T &)
  879. {
  880. return {};
  881. }
  882. template <typename T>
  883. std::vector<std::string> MapKeysToStrings(const T &map)
  884. {
  885. std::vector<std::string> res;
  886. using K = typename std::decay<decltype(std::begin(map)->first)>::type;
  887. if (IsConvertableToString<K>::value)
  888. {
  889. for (const auto &p : map)
  890. {
  891. res.push_back(detail::ToString(p.first));
  892. }
  893. std::sort(res.begin(), res.end());
  894. }
  895. return res;
  896. }
  897. }
  898. /** Base class for all flag options
  899. */
  900. class FlagBase : public NamedBase
  901. {
  902. protected:
  903. const Matcher matcher;
  904. virtual std::string GetNameString(const HelpParams &params) const override
  905. {
  906. const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name();
  907. std::string flags;
  908. const auto flagStrings = matcher.GetFlagStrings();
  909. const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce;
  910. for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it)
  911. {
  912. auto &flag = *it;
  913. if (it != flagStrings.begin())
  914. {
  915. flags += ", ";
  916. }
  917. flags += flag.isShort ? params.shortPrefix : params.longPrefix;
  918. flags += flag.str();
  919. if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end()))
  920. {
  921. flags += flag.isShort ? params.shortSeparator : params.longSeparator;
  922. flags += params.valueOpen + postfix + params.valueClose;
  923. }
  924. }
  925. return flags;
  926. }
  927. public:
  928. 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_)) {}
  929. FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {}
  930. virtual ~FlagBase() {}
  931. virtual FlagBase *Match(const EitherFlag &flag) override
  932. {
  933. if (matcher.Match(flag))
  934. {
  935. if ((GetOptions() & Options::Single) != Options::None && matched)
  936. {
  937. std::ostringstream problem;
  938. problem << "Flag '" << flag.str() << "' was passed multiple times, but is only allowed to be passed once";
  939. #ifdef ARGS_NOEXCEPT
  940. error = Error::Extra;
  941. errorMsg = problem.str();
  942. #else
  943. throw ExtraError(problem.str());
  944. #endif
  945. }
  946. matched = true;
  947. return this;
  948. }
  949. return nullptr;
  950. }
  951. virtual std::vector<FlagBase*> GetAllFlags() override
  952. {
  953. return { this };
  954. }
  955. const Matcher &GetMatcher() const
  956. {
  957. return matcher;
  958. }
  959. virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
  960. {
  961. if (!Matched() && IsRequired())
  962. {
  963. std::ostringstream problem;
  964. problem << "Flag '" << matcher.GetLongOrAny().str(shortPrefix, longPrefix) << "' is required";
  965. #ifdef ARGS_NOEXCEPT
  966. error = Error::Required;
  967. errorMsg = problem.str();
  968. #else
  969. throw RequiredError(problem.str());
  970. #endif
  971. }
  972. }
  973. virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
  974. {
  975. if (!params.proglineShowFlags)
  976. {
  977. return {};
  978. }
  979. const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name();
  980. const EitherFlag flag = params.proglinePreferShortFlags ? matcher.GetShortOrAny() : matcher.GetLongOrAny();
  981. std::string res = flag.str(params.shortPrefix, params.longPrefix);
  982. if (!postfix.empty())
  983. {
  984. res += params.proglineValueOpen + postfix + params.proglineValueClose;
  985. }
  986. return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose
  987. : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose };
  988. }
  989. virtual bool HasFlag() const override
  990. {
  991. return true;
  992. }
  993. #ifdef ARGS_NOEXCEPT
  994. /// Only for ARGS_NOEXCEPT
  995. virtual Error GetError() const override
  996. {
  997. const auto nargs = NumberOfArguments();
  998. if (nargs.min > nargs.max)
  999. {
  1000. return Error::Usage;
  1001. }
  1002. const auto matcherError = matcher.GetError();
  1003. if (matcherError != Error::None)
  1004. {
  1005. return matcherError;
  1006. }
  1007. return error;
  1008. }
  1009. #endif
  1010. /** Defines how many values can be consumed by this option.
  1011. *
  1012. * \return closed interval [min, max]
  1013. */
  1014. virtual Nargs NumberOfArguments() const noexcept = 0;
  1015. /** Parse values of this option.
  1016. *
  1017. * \param value Vector of values. It's size must be in NumberOfArguments() interval.
  1018. */
  1019. virtual void ParseValue(const std::vector<std::string> &value) = 0;
  1020. };
  1021. /** Base class for value-accepting flag options
  1022. */
  1023. class ValueFlagBase : public FlagBase
  1024. {
  1025. public:
  1026. ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : FlagBase(name_, help_, std::move(matcher_), extraError_) {}
  1027. ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : FlagBase(name_, help_, std::move(matcher_), options_) {}
  1028. virtual ~ValueFlagBase() {}
  1029. virtual Nargs NumberOfArguments() const noexcept override
  1030. {
  1031. return 1;
  1032. }
  1033. };
  1034. class CompletionFlag : public ValueFlagBase
  1035. {
  1036. public:
  1037. std::vector<std::string> reply;
  1038. size_t cword = 0;
  1039. std::string syntax;
  1040. template <typename GroupClass>
  1041. CompletionFlag(GroupClass &group_, Matcher &&matcher_): ValueFlagBase("completion", "completion flag", std::move(matcher_), Options::Hidden)
  1042. {
  1043. group_.AddCompletion(*this);
  1044. }
  1045. virtual ~CompletionFlag() {}
  1046. virtual Nargs NumberOfArguments() const noexcept override
  1047. {
  1048. return 2;
  1049. }
  1050. virtual void ParseValue(const std::vector<std::string> &value_) override
  1051. {
  1052. syntax = value_.at(0);
  1053. std::istringstream(value_.at(1)) >> cword;
  1054. }
  1055. /** Get the completion reply
  1056. */
  1057. std::string Get() noexcept
  1058. {
  1059. return detail::Join(reply, "\n");
  1060. }
  1061. virtual void Reset() noexcept override
  1062. {
  1063. ValueFlagBase::Reset();
  1064. cword = 0;
  1065. syntax.clear();
  1066. reply.clear();
  1067. }
  1068. };
  1069. /** Base class for positional options
  1070. */
  1071. class PositionalBase : public NamedBase
  1072. {
  1073. protected:
  1074. bool ready;
  1075. public:
  1076. PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {}
  1077. virtual ~PositionalBase() {}
  1078. bool Ready()
  1079. {
  1080. return ready;
  1081. }
  1082. virtual void ParseValue(const std::string &value_) = 0;
  1083. virtual void Reset() noexcept override
  1084. {
  1085. matched = false;
  1086. ready = true;
  1087. #ifdef ARGS_NOEXCEPT
  1088. error = Error::None;
  1089. errorMsg.clear();
  1090. #endif
  1091. }
  1092. virtual PositionalBase *GetNextPositional() override
  1093. {
  1094. return Ready() ? this : nullptr;
  1095. }
  1096. virtual bool HasPositional() const override
  1097. {
  1098. return true;
  1099. }
  1100. virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
  1101. {
  1102. return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose
  1103. : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose };
  1104. }
  1105. virtual void Validate(const std::string &, const std::string &) const override
  1106. {
  1107. if (IsRequired() && !Matched())
  1108. {
  1109. std::ostringstream problem;
  1110. problem << "Option '" << Name() << "' is required";
  1111. #ifdef ARGS_NOEXCEPT
  1112. error = Error::Required;
  1113. errorMsg = problem.str();
  1114. #else
  1115. throw RequiredError(problem.str());
  1116. #endif
  1117. }
  1118. }
  1119. };
  1120. /** Class for all kinds of validating groups, including ArgumentParser
  1121. */
  1122. class Group : public Base
  1123. {
  1124. private:
  1125. std::vector<Base*> children;
  1126. std::function<bool(const Group &)> validator;
  1127. public:
  1128. /** Default validators
  1129. */
  1130. struct Validators
  1131. {
  1132. static bool Xor(const Group &group)
  1133. {
  1134. return group.MatchedChildren() == 1;
  1135. }
  1136. static bool AtLeastOne(const Group &group)
  1137. {
  1138. return group.MatchedChildren() >= 1;
  1139. }
  1140. static bool AtMostOne(const Group &group)
  1141. {
  1142. return group.MatchedChildren() <= 1;
  1143. }
  1144. static bool All(const Group &group)
  1145. {
  1146. return group.Children().size() == group.MatchedChildren();
  1147. }
  1148. static bool AllOrNone(const Group &group)
  1149. {
  1150. return (All(group) || None(group));
  1151. }
  1152. static bool AllChildGroups(const Group &group)
  1153. {
  1154. return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool {
  1155. return child->IsGroup() && !child->Matched();
  1156. });
  1157. }
  1158. static bool DontCare(const Group &)
  1159. {
  1160. return true;
  1161. }
  1162. static bool CareTooMuch(const Group &)
  1163. {
  1164. return false;
  1165. }
  1166. static bool None(const Group &group)
  1167. {
  1168. return group.MatchedChildren() == 0;
  1169. }
  1170. };
  1171. /// If help is empty, this group will not be printed in help output
  1172. Group(const std::string &help_ = std::string(), const std::function<bool(const Group &)> &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) {}
  1173. /// If help is empty, this group will not be printed in help output
  1174. 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_)
  1175. {
  1176. group_.Add(*this);
  1177. }
  1178. virtual ~Group() {}
  1179. /** Append a child to this Group.
  1180. */
  1181. void Add(Base &child)
  1182. {
  1183. children.emplace_back(&child);
  1184. }
  1185. /** Get all this group's children
  1186. */
  1187. const std::vector<Base *> &Children() const
  1188. {
  1189. return children;
  1190. }
  1191. /** Return the first FlagBase that matches flag, or nullptr
  1192. *
  1193. * \param flag The flag with prefixes stripped
  1194. * \return the first matching FlagBase pointer, or nullptr if there is no match
  1195. */
  1196. virtual FlagBase *Match(const EitherFlag &flag) override
  1197. {
  1198. for (Base *child: Children())
  1199. {
  1200. if (FlagBase *match = child->Match(flag))
  1201. {
  1202. return match;
  1203. }
  1204. }
  1205. return nullptr;
  1206. }
  1207. virtual std::vector<FlagBase*> GetAllFlags() override
  1208. {
  1209. std::vector<FlagBase*> res;
  1210. for (Base *child: Children())
  1211. {
  1212. auto childRes = child->GetAllFlags();
  1213. res.insert(res.end(), childRes.begin(), childRes.end());
  1214. }
  1215. return res;
  1216. }
  1217. virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override
  1218. {
  1219. for (Base *child: Children())
  1220. {
  1221. child->Validate(shortPrefix, longPrefix);
  1222. }
  1223. }
  1224. /** Get the next ready positional, or nullptr if there is none
  1225. *
  1226. * \return the first ready PositionalBase pointer, or nullptr if there is no match
  1227. */
  1228. virtual PositionalBase *GetNextPositional() override
  1229. {
  1230. for (Base *child: Children())
  1231. {
  1232. if (auto next = child->GetNextPositional())
  1233. {
  1234. return next;
  1235. }
  1236. }
  1237. return nullptr;
  1238. }
  1239. /** Get whether this has any FlagBase children
  1240. *
  1241. * \return Whether or not there are any FlagBase children
  1242. */
  1243. virtual bool HasFlag() const override
  1244. {
  1245. return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); });
  1246. }
  1247. /** Get whether this has any PositionalBase children
  1248. *
  1249. * \return Whether or not there are any PositionalBase children
  1250. */
  1251. virtual bool HasPositional() const override
  1252. {
  1253. return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); });
  1254. }
  1255. /** Get whether this has any Command children
  1256. *
  1257. * \return Whether or not there are any Command children
  1258. */
  1259. virtual bool HasCommand() const override
  1260. {
  1261. return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); });
  1262. }
  1263. /** Count the number of matched children this group has
  1264. */
  1265. std::vector<Base *>::size_type MatchedChildren() const
  1266. {
  1267. // Cast to avoid warnings from -Wsign-conversion
  1268. return static_cast<std::vector<Base *>::size_type>(
  1269. std::count_if(std::begin(Children()), std::end(Children()), [](const Base *child){return child->Matched();}));
  1270. }
  1271. /** Whether or not this group matches validation
  1272. */
  1273. virtual bool Matched() const noexcept override
  1274. {
  1275. return validator(*this);
  1276. }
  1277. /** Get validation
  1278. */
  1279. bool Get() const
  1280. {
  1281. return Matched();
  1282. }
  1283. /** Get all the child descriptions for help generation
  1284. */
  1285. virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
  1286. {
  1287. std::vector<std::tuple<std::string, std::string, unsigned int>> descriptions;
  1288. // Push that group description on the back if not empty
  1289. unsigned addindent = 0;
  1290. if (!help.empty())
  1291. {
  1292. descriptions.emplace_back(help, "", indent);
  1293. addindent = 1;
  1294. }
  1295. for (Base *child: Children())
  1296. {
  1297. if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
  1298. {
  1299. continue;
  1300. }
  1301. auto groupDescriptions = child->GetDescription(params, indent + addindent);
  1302. descriptions.insert(
  1303. std::end(descriptions),
  1304. std::make_move_iterator(std::begin(groupDescriptions)),
  1305. std::make_move_iterator(std::end(groupDescriptions)));
  1306. }
  1307. return descriptions;
  1308. }
  1309. /** Get the names of positional parameters
  1310. */
  1311. virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
  1312. {
  1313. std::vector <std::string> names;
  1314. for (Base *child: Children())
  1315. {
  1316. if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None)
  1317. {
  1318. continue;
  1319. }
  1320. auto groupNames = child->GetProgramLine(params);
  1321. names.insert(
  1322. std::end(names),
  1323. std::make_move_iterator(std::begin(groupNames)),
  1324. std::make_move_iterator(std::end(groupNames)));
  1325. }
  1326. return names;
  1327. }
  1328. virtual std::vector<Command*> GetCommands() override
  1329. {
  1330. std::vector<Command*> res;
  1331. for (const auto &child : Children())
  1332. {
  1333. auto subparsers = child->GetCommands();
  1334. res.insert(std::end(res), std::begin(subparsers), std::end(subparsers));
  1335. }
  1336. return res;
  1337. }
  1338. virtual bool IsGroup() const override
  1339. {
  1340. return true;
  1341. }
  1342. virtual void Reset() noexcept override
  1343. {
  1344. Base::Reset();
  1345. for (auto &child: Children())
  1346. {
  1347. child->Reset();
  1348. }
  1349. #ifdef ARGS_NOEXCEPT
  1350. error = Error::None;
  1351. errorMsg.clear();
  1352. #endif
  1353. }
  1354. #ifdef ARGS_NOEXCEPT
  1355. /// Only for ARGS_NOEXCEPT
  1356. virtual Error GetError() const override
  1357. {
  1358. if (error != Error::None)
  1359. {
  1360. return error;
  1361. }
  1362. auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;});
  1363. if (it == Children().end())
  1364. {
  1365. return Error::None;
  1366. } else
  1367. {
  1368. return (*it)->GetError();
  1369. }
  1370. }
  1371. #endif
  1372. };
  1373. /** Class for using global options in ArgumentParser.
  1374. */
  1375. class GlobalOptions : public Group
  1376. {
  1377. public:
  1378. GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global)
  1379. {
  1380. Add(options_);
  1381. }
  1382. };
  1383. /** Utility class for building subparsers with coroutines/callbacks.
  1384. *
  1385. * Brief example:
  1386. * \code
  1387. * Command command(argumentParser, "command", "my command", [](args::Subparser &s)
  1388. * {
  1389. * // your command flags/positionals
  1390. * s.Parse(); //required
  1391. * //your command code
  1392. * });
  1393. * \endcode
  1394. *
  1395. * For ARGS_NOEXCEPT mode don't forget to check `s.GetError()` after `s.Parse()`
  1396. * and return if it isn't equals to args::Error::None.
  1397. *
  1398. * \sa Command
  1399. */
  1400. class Subparser : public Group
  1401. {
  1402. private:
  1403. std::vector<std::string> args;
  1404. std::vector<std::string> kicked;
  1405. ArgumentParser *parser = nullptr;
  1406. const HelpParams &helpParams;
  1407. const Command &command;
  1408. bool isParsed = false;
  1409. public:
  1410. Subparser(std::vector<std::string> args_, ArgumentParser &parser_, const Command &command_, const HelpParams &helpParams_)
  1411. : Group({}, Validators::AllChildGroups), args(std::move(args_)), parser(&parser_), helpParams(helpParams_), command(command_)
  1412. {
  1413. }
  1414. Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_)
  1415. {
  1416. }
  1417. Subparser(const Subparser&) = delete;
  1418. Subparser(Subparser&&) = delete;
  1419. Subparser &operator = (const Subparser&) = delete;
  1420. Subparser &operator = (Subparser&&) = delete;
  1421. const Command &GetCommand()
  1422. {
  1423. return command;
  1424. }
  1425. /** (INTERNAL) Determines whether Parse was called or not.
  1426. */
  1427. bool IsParsed() const
  1428. {
  1429. return isParsed;
  1430. }
  1431. /** Continue parsing arguments for new command.
  1432. */
  1433. void Parse();
  1434. /** Returns a vector of kicked out arguments.
  1435. *
  1436. * \sa Base::KickOut
  1437. */
  1438. const std::vector<std::string> &KickedOut() const noexcept
  1439. {
  1440. return kicked;
  1441. }
  1442. };
  1443. /** Main class for building subparsers.
  1444. *
  1445. * /sa Subparser
  1446. */
  1447. class Command : public Group
  1448. {
  1449. private:
  1450. friend class Subparser;
  1451. std::string name;
  1452. std::string help;
  1453. std::string description;
  1454. std::string epilog;
  1455. std::string proglinePostfix;
  1456. std::function<void(Subparser&)> parserCoroutine;
  1457. bool commandIsRequired = true;
  1458. Command *selectedCommand = nullptr;
  1459. mutable std::vector<std::tuple<std::string, std::string, unsigned>> subparserDescription;
  1460. mutable std::vector<std::string> subparserProgramLine;
  1461. mutable bool subparserHasFlag = false;
  1462. mutable bool subparserHasPositional = false;
  1463. mutable bool subparserHasCommand = false;
  1464. #ifdef ARGS_NOEXCEPT
  1465. mutable Error subparserError = Error::None;
  1466. #endif
  1467. mutable Subparser *subparser = nullptr;
  1468. protected:
  1469. class RaiiSubparser
  1470. {
  1471. public:
  1472. RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_);
  1473. RaiiSubparser(const Command &command_, const HelpParams &params_);
  1474. ~RaiiSubparser()
  1475. {
  1476. command.subparser = oldSubparser;
  1477. }
  1478. Subparser &Parser()
  1479. {
  1480. return parser;
  1481. }
  1482. private:
  1483. const Command &command;
  1484. Subparser parser;
  1485. Subparser *oldSubparser;
  1486. };
  1487. Command() = default;
  1488. std::function<void(Subparser&)> &GetCoroutine()
  1489. {
  1490. return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine;
  1491. }
  1492. Command &SelectedCommand()
  1493. {
  1494. Command *res = this;
  1495. while (res->selectedCommand != nullptr)
  1496. {
  1497. res = res->selectedCommand;
  1498. }
  1499. return *res;
  1500. }
  1501. const Command &SelectedCommand() const
  1502. {
  1503. const Command *res = this;
  1504. while (res->selectedCommand != nullptr)
  1505. {
  1506. res = res->selectedCommand;
  1507. }
  1508. return *res;
  1509. }
  1510. void UpdateSubparserHelp(const HelpParams &params) const
  1511. {
  1512. if (parserCoroutine)
  1513. {
  1514. RaiiSubparser coro(*this, params);
  1515. #ifndef ARGS_NOEXCEPT
  1516. try
  1517. {
  1518. parserCoroutine(coro.Parser());
  1519. }
  1520. catch (args::SubparserError&)
  1521. {
  1522. }
  1523. #else
  1524. parserCoroutine(coro.Parser());
  1525. #endif
  1526. }
  1527. }
  1528. public:
  1529. Command(Group &base_, std::string name_, std::string help_, std::function<void(Subparser&)> coroutine_ = {})
  1530. : name(std::move(name_)), help(std::move(help_)), parserCoroutine(std::move(coroutine_))
  1531. {
  1532. base_.Add(*this);
  1533. }
  1534. /** The description that appears on the prog line after options
  1535. */
  1536. const std::string &ProglinePostfix() const
  1537. { return proglinePostfix; }
  1538. /** The description that appears on the prog line after options
  1539. */
  1540. void ProglinePostfix(const std::string &proglinePostfix_)
  1541. { this->proglinePostfix = proglinePostfix_; }
  1542. /** The description that appears above options
  1543. */
  1544. const std::string &Description() const
  1545. { return description; }
  1546. /** The description that appears above options
  1547. */
  1548. void Description(const std::string &description_)
  1549. { this->description = description_; }
  1550. /** The description that appears below options
  1551. */
  1552. const std::string &Epilog() const
  1553. { return epilog; }
  1554. /** The description that appears below options
  1555. */
  1556. void Epilog(const std::string &epilog_)
  1557. { this->epilog = epilog_; }
  1558. /** The name of command
  1559. */
  1560. const std::string &Name() const
  1561. { return name; }
  1562. /** The description of command
  1563. */
  1564. const std::string &Help() const
  1565. { return help; }
  1566. /** If value is true, parser will fail if no command was parsed.
  1567. *
  1568. * Default: true.
  1569. */
  1570. void RequireCommand(bool value)
  1571. { commandIsRequired = value; }
  1572. virtual bool IsGroup() const override
  1573. { return false; }
  1574. virtual bool Matched() const noexcept override
  1575. { return Base::Matched(); }
  1576. operator bool() const noexcept
  1577. { return Matched(); }
  1578. void Match() noexcept
  1579. { matched = true; }
  1580. void SelectCommand(Command *c) noexcept
  1581. {
  1582. selectedCommand = c;
  1583. if (c != nullptr)
  1584. {
  1585. c->Match();
  1586. }
  1587. }
  1588. virtual FlagBase *Match(const EitherFlag &flag) override
  1589. {
  1590. if (selectedCommand != nullptr)
  1591. {
  1592. if (auto *res = selectedCommand->Match(flag))
  1593. {
  1594. return res;
  1595. }
  1596. for (auto *child: Children())
  1597. {
  1598. if ((child->GetOptions() & Options::Global) != Options::None)
  1599. {
  1600. if (auto *res = child->Match(flag))
  1601. {
  1602. return res;
  1603. }
  1604. }
  1605. }
  1606. return nullptr;
  1607. }
  1608. if (subparser != nullptr)
  1609. {
  1610. return subparser->Match(flag);
  1611. }
  1612. return Matched() ? Group::Match(flag) : nullptr;
  1613. }
  1614. virtual std::vector<FlagBase*> GetAllFlags() override
  1615. {
  1616. std::vector<FlagBase*> res;
  1617. if (!Matched())
  1618. {
  1619. return res;
  1620. }
  1621. for (auto *child: Children())
  1622. {
  1623. if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None)
  1624. {
  1625. auto childFlags = child->GetAllFlags();
  1626. res.insert(res.end(), childFlags.begin(), childFlags.end());
  1627. }
  1628. }
  1629. if (selectedCommand != nullptr)
  1630. {
  1631. auto childFlags = selectedCommand->GetAllFlags();
  1632. res.insert(res.end(), childFlags.begin(), childFlags.end());
  1633. }
  1634. if (subparser != nullptr)
  1635. {
  1636. auto childFlags = subparser->GetAllFlags();
  1637. res.insert(res.end(), childFlags.begin(), childFlags.end());
  1638. }
  1639. return res;
  1640. }
  1641. virtual PositionalBase *GetNextPositional() override
  1642. {
  1643. if (selectedCommand != nullptr)
  1644. {
  1645. if (auto *res = selectedCommand->GetNextPositional())
  1646. {
  1647. return res;
  1648. }
  1649. for (auto *child: Children())
  1650. {
  1651. if ((child->GetOptions() & Options::Global) != Options::None)
  1652. {
  1653. if (auto *res = child->GetNextPositional())
  1654. {
  1655. return res;
  1656. }
  1657. }
  1658. }
  1659. return nullptr;
  1660. }
  1661. if (subparser != nullptr)
  1662. {
  1663. return subparser->GetNextPositional();
  1664. }
  1665. return Matched() ? Group::GetNextPositional() : nullptr;
  1666. }
  1667. virtual bool HasFlag() const override
  1668. {
  1669. return subparserHasFlag || Group::HasFlag();
  1670. }
  1671. virtual bool HasPositional() const override
  1672. {
  1673. return subparserHasPositional || Group::HasPositional();
  1674. }
  1675. virtual bool HasCommand() const override
  1676. {
  1677. return true;
  1678. }
  1679. std::vector<std::string> GetCommandProgramLine(const HelpParams &params) const
  1680. {
  1681. UpdateSubparserHelp(params);
  1682. auto res = Group::GetProgramLine(params);
  1683. res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end());
  1684. if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand))
  1685. {
  1686. res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]");
  1687. }
  1688. if (!Name().empty())
  1689. {
  1690. res.insert(res.begin(), Name());
  1691. }
  1692. if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags)
  1693. {
  1694. res.push_back(params.proglineOptions);
  1695. }
  1696. if (!ProglinePostfix().empty())
  1697. {
  1698. std::string line;
  1699. for (char c : ProglinePostfix())
  1700. {
  1701. if (isspace(c))
  1702. {
  1703. if (!line.empty())
  1704. {
  1705. res.push_back(line);
  1706. line.clear();
  1707. }
  1708. if (c == '\n')
  1709. {
  1710. res.push_back("\n");
  1711. }
  1712. }
  1713. else
  1714. {
  1715. line += c;
  1716. }
  1717. }
  1718. if (!line.empty())
  1719. {
  1720. res.push_back(line);
  1721. }
  1722. }
  1723. return res;
  1724. }
  1725. virtual std::vector<std::string> GetProgramLine(const HelpParams &params) const override
  1726. {
  1727. if (!Matched())
  1728. {
  1729. return {};
  1730. }
  1731. return GetCommandProgramLine(params);
  1732. }
  1733. virtual std::vector<Command*> GetCommands() override
  1734. {
  1735. if (selectedCommand != nullptr)
  1736. {
  1737. return selectedCommand->GetCommands();
  1738. }
  1739. if (Matched())
  1740. {
  1741. return Group::GetCommands();
  1742. }
  1743. return { this };
  1744. }
  1745. virtual std::vector<std::tuple<std::string, std::string, unsigned>> GetDescription(const HelpParams &params, const unsigned int indent) const override
  1746. {
  1747. std::vector<std::tuple<std::string, std::string, unsigned>> descriptions;
  1748. unsigned addindent = 0;
  1749. UpdateSubparserHelp(params);
  1750. if (!Matched())
  1751. {
  1752. if (params.showCommandFullHelp)
  1753. {
  1754. std::ostringstream s;
  1755. bool empty = true;
  1756. for (const auto &progline: GetCommandProgramLine(params))
  1757. {
  1758. if (!empty)
  1759. {
  1760. s << ' ';
  1761. }
  1762. else
  1763. {
  1764. empty = false;
  1765. }
  1766. s << progline;
  1767. }
  1768. descriptions.emplace_back(s.str(), "", indent);
  1769. }
  1770. else
  1771. {
  1772. descriptions.emplace_back(Name(), help, indent);
  1773. }
  1774. if (!params.showCommandChildren && !params.showCommandFullHelp)
  1775. {
  1776. return descriptions;
  1777. }
  1778. addindent = 1;
  1779. }
  1780. if (params.showCommandFullHelp && !Matched())
  1781. {
  1782. descriptions.emplace_back("", "", indent + addindent);
  1783. descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent);
  1784. descriptions.emplace_back("", "", indent + addindent);
  1785. }
  1786. for (Base *child: Children())
  1787. {
  1788. if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None)
  1789. {
  1790. continue;
  1791. }
  1792. auto groupDescriptions = child->GetDescription(params, indent + addindent);
  1793. descriptions.insert(
  1794. std::end(descriptions),
  1795. std::make_move_iterator(std::begin(groupDescriptions)),
  1796. std::make_move_iterator(std::end(groupDescriptions)));
  1797. }
  1798. for (auto childDescription: subparserDescription)
  1799. {
  1800. std::get<2>(childDescription) += indent + addindent;
  1801. descriptions.push_back(std::move(childDescription));
  1802. }
  1803. if (params.showCommandFullHelp && !Matched())
  1804. {
  1805. descriptions.emplace_back("", "", indent + addindent);
  1806. if (!Epilog().empty())
  1807. {
  1808. descriptions.emplace_back(Epilog(), "", indent + addindent);
  1809. descriptions.emplace_back("", "", indent + addindent);
  1810. }
  1811. }
  1812. return descriptions;
  1813. }
  1814. virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override
  1815. {
  1816. if (!Matched())
  1817. {
  1818. return;
  1819. }
  1820. auto onValidationError = [&]
  1821. {
  1822. std::ostringstream problem;
  1823. problem << "Group validation failed somewhere!";
  1824. #ifdef ARGS_NOEXCEPT
  1825. error = Error::Validation;
  1826. errorMsg = problem.str();
  1827. #else
  1828. throw ValidationError(problem.str());
  1829. #endif
  1830. };
  1831. for (Base *child: Children())
  1832. {
  1833. if (child->IsGroup() && !child->Matched())
  1834. {
  1835. onValidationError();
  1836. }
  1837. child->Validate(shortprefix, longprefix);
  1838. }
  1839. if (subparser != nullptr)
  1840. {
  1841. subparser->Validate(shortprefix, longprefix);
  1842. if (!subparser->Matched())
  1843. {
  1844. onValidationError();
  1845. }
  1846. }
  1847. if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand))
  1848. {
  1849. std::ostringstream problem;
  1850. problem << "Command is required";
  1851. #ifdef ARGS_NOEXCEPT
  1852. error = Error::Validation;
  1853. errorMsg = problem.str();
  1854. #else
  1855. throw ValidationError(problem.str());
  1856. #endif
  1857. }
  1858. }
  1859. virtual void Reset() noexcept override
  1860. {
  1861. Group::Reset();
  1862. selectedCommand = nullptr;
  1863. subparserProgramLine.clear();
  1864. subparserDescription.clear();
  1865. subparserHasFlag = false;
  1866. subparserHasPositional = false;
  1867. subparserHasCommand = false;
  1868. #ifdef ARGS_NOEXCEPT
  1869. subparserError = Error::None;
  1870. #endif
  1871. }
  1872. #ifdef ARGS_NOEXCEPT
  1873. /// Only for ARGS_NOEXCEPT
  1874. virtual Error GetError() const override
  1875. {
  1876. if (!Matched())
  1877. {
  1878. return Error::None;
  1879. }
  1880. if (error != Error::None)
  1881. {
  1882. return error;
  1883. }
  1884. if (subparserError != Error::None)
  1885. {
  1886. return subparserError;
  1887. }
  1888. return Group::GetError();
  1889. }
  1890. #endif
  1891. };
  1892. /** The main user facing command line argument parser class
  1893. */
  1894. class ArgumentParser : public Command
  1895. {
  1896. friend class Subparser;
  1897. private:
  1898. std::string longprefix;
  1899. std::string shortprefix;
  1900. std::string longseparator;
  1901. std::string terminator;
  1902. bool allowJoinedShortValue = true;
  1903. bool allowJoinedLongValue = true;
  1904. bool allowSeparateShortValue = true;
  1905. bool allowSeparateLongValue = true;
  1906. CompletionFlag *completion = nullptr;
  1907. bool readCompletion = false;
  1908. protected:
  1909. enum class OptionType
  1910. {
  1911. LongFlag,
  1912. ShortFlag,
  1913. Positional
  1914. };
  1915. OptionType ParseOption(const std::string &s, bool allowEmpty = false)
  1916. {
  1917. if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length()))
  1918. {
  1919. return OptionType::LongFlag;
  1920. }
  1921. if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length()))
  1922. {
  1923. return OptionType::ShortFlag;
  1924. }
  1925. return OptionType::Positional;
  1926. }
  1927. template <typename It>
  1928. bool Complete(FlagBase &flag, It it, It end)
  1929. {
  1930. auto nextIt = it;
  1931. if (!readCompletion || (++nextIt != end))
  1932. {
  1933. return false;
  1934. }
  1935. const auto &chunk = *it;
  1936. for (auto &choice : flag.HelpChoices(helpParams))
  1937. {
  1938. AddCompletionReply(chunk, choice);
  1939. }
  1940. #ifndef ARGS_NOEXCEPT
  1941. throw Completion(completion->Get());
  1942. #else
  1943. return true;
  1944. #endif
  1945. }
  1946. /** (INTERNAL) Parse flag's values
  1947. *
  1948. * \param arg The string to display in error message as a flag name
  1949. * \param[in, out] it The iterator to first value. It will point to the last value
  1950. * \param end The end iterator
  1951. * \param joinedArg Joined value (e.g. bar in --foo=bar)
  1952. * \param canDiscardJoined If true joined value can be parsed as flag not as a value (as in -abcd)
  1953. * \param[out] values The vector to store parsed arg's values
  1954. */
  1955. template <typename It>
  1956. std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end,
  1957. const bool allowSeparate, const bool allowJoined,
  1958. const bool hasJoined, const std::string &joinedArg,
  1959. const bool canDiscardJoined, std::vector<std::string> &values)
  1960. {
  1961. values.clear();
  1962. Nargs nargs = flag.NumberOfArguments();
  1963. if (hasJoined && !allowJoined && nargs.min != 0)
  1964. {
  1965. return "Flag '" + arg + "' was passed a joined argument, but these are disallowed";
  1966. }
  1967. if (hasJoined)
  1968. {
  1969. if (!canDiscardJoined || nargs.max != 0)
  1970. {
  1971. values.push_back(joinedArg);
  1972. }
  1973. } else if (!allowSeparate)
  1974. {
  1975. if (nargs.min != 0)
  1976. {
  1977. return "Flag '" + arg + "' was passed a separate argument, but these are disallowed";
  1978. }
  1979. } else
  1980. {
  1981. auto valueIt = it;
  1982. ++valueIt;
  1983. while (valueIt != end &&
  1984. values.size() < nargs.max &&
  1985. (nargs.min == nargs.max || ParseOption(*valueIt) == OptionType::Positional))
  1986. {
  1987. if (Complete(flag, valueIt, end))
  1988. {
  1989. it = end;
  1990. return "";
  1991. }
  1992. values.push_back(*valueIt);
  1993. ++it;
  1994. ++valueIt;
  1995. }
  1996. }
  1997. if (values.size() > nargs.max)
  1998. {
  1999. return "Passed an argument into a non-argument flag: " + arg;
  2000. } else if (values.size() < nargs.min)
  2001. {
  2002. if (nargs.min == 1 && nargs.max == 1)
  2003. {
  2004. return "Flag '" + arg + "' requires an argument but received none";
  2005. } else if (nargs.min == 1)
  2006. {
  2007. return "Flag '" + arg + "' requires at least one argument but received none";
  2008. } else if (nargs.min != nargs.max)
  2009. {
  2010. return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) +
  2011. " arguments but received " + std::to_string(values.size());
  2012. } else
  2013. {
  2014. return "Flag '" + arg + "' requires " + std::to_string(nargs.min) +
  2015. " arguments but received " + std::to_string(values.size());
  2016. }
  2017. }
  2018. return {};
  2019. }
  2020. template <typename It>
  2021. bool ParseLong(It &it, It end)
  2022. {
  2023. const auto &chunk = *it;
  2024. const auto argchunk = chunk.substr(longprefix.size());
  2025. // Try to separate it, in case of a separator:
  2026. const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator);
  2027. // If the separator is in the argument, separate it.
  2028. const auto arg = (separator != argchunk.npos ?
  2029. std::string(argchunk, 0, separator)
  2030. : argchunk);
  2031. const auto joined = (separator != argchunk.npos ?
  2032. argchunk.substr(separator + longseparator.size())
  2033. : std::string());
  2034. if (auto flag = Match(arg))
  2035. {
  2036. std::vector<std::string> values;
  2037. const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue,
  2038. separator != argchunk.npos, joined, false, values);
  2039. if (!errorMessage.empty())
  2040. {
  2041. #ifndef ARGS_NOEXCEPT
  2042. throw ParseError(errorMessage);
  2043. #else
  2044. error = Error::Parse;
  2045. errorMsg = errorMessage;
  2046. return false;
  2047. #endif
  2048. }
  2049. if (!readCompletion)
  2050. {
  2051. flag->ParseValue(values);
  2052. }
  2053. if (flag->KickOut())
  2054. {
  2055. ++it;
  2056. return false;
  2057. }
  2058. } else
  2059. {
  2060. const std::string errorMessage("Flag could not be matched: " + arg);
  2061. #ifndef ARGS_NOEXCEPT
  2062. throw ParseError(errorMessage);
  2063. #else
  2064. error = Error::Parse;
  2065. errorMsg = errorMessage;
  2066. return false;
  2067. #endif
  2068. }
  2069. return true;
  2070. }
  2071. template <typename It>
  2072. bool ParseShort(It &it, It end)
  2073. {
  2074. const auto &chunk = *it;
  2075. const auto argchunk = chunk.substr(shortprefix.size());
  2076. for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit)
  2077. {
  2078. const auto arg = *argit;
  2079. if (auto flag = Match(arg))
  2080. {
  2081. const std::string value(argit + 1, std::end(argchunk));
  2082. std::vector<std::string> values;
  2083. const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end,
  2084. allowSeparateShortValue, allowJoinedShortValue,
  2085. !value.empty(), value, !value.empty(), values);
  2086. if (!errorMessage.empty())
  2087. {
  2088. #ifndef ARGS_NOEXCEPT
  2089. throw ParseError(errorMessage);
  2090. #else
  2091. error = Error::Parse;
  2092. errorMsg = errorMessage;
  2093. return false;
  2094. #endif
  2095. }
  2096. if (!readCompletion)
  2097. {
  2098. flag->ParseValue(values);
  2099. }
  2100. if (flag->KickOut())
  2101. {
  2102. ++it;
  2103. return false;
  2104. }
  2105. if (!values.empty())
  2106. {
  2107. break;
  2108. }
  2109. } else
  2110. {
  2111. const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'");
  2112. #ifndef ARGS_NOEXCEPT
  2113. throw ParseError(errorMessage);
  2114. #else
  2115. error = Error::Parse;
  2116. errorMsg = errorMessage;
  2117. return false;
  2118. #endif
  2119. }
  2120. }
  2121. return true;
  2122. }
  2123. bool AddCompletionReply(const std::string &cur, const std::string &choice)
  2124. {
  2125. if (cur.empty() || choice.find(cur) == 0)
  2126. {
  2127. if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos)
  2128. {
  2129. completion->reply.push_back(choice.substr(choice.find(longseparator) + 1));
  2130. } else
  2131. {
  2132. completion->reply.push_back(choice);
  2133. }
  2134. return true;
  2135. }
  2136. return false;
  2137. }
  2138. template <typename It>
  2139. bool Complete(It it, It end)
  2140. {
  2141. auto nextIt = it;
  2142. if (!readCompletion || (++nextIt != end))
  2143. {
  2144. return false;
  2145. }
  2146. const auto &chunk = *it;
  2147. auto pos = GetNextPositional();
  2148. std::vector<Command *> commands = GetCommands();
  2149. const auto optionType = ParseOption(chunk, true);
  2150. if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
  2151. {
  2152. for (auto &cmd : commands)
  2153. {
  2154. if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
  2155. {
  2156. AddCompletionReply(chunk, cmd->Name());
  2157. }
  2158. }
  2159. } else
  2160. {
  2161. bool hasPositionalCompletion = true;
  2162. if (!commands.empty())
  2163. {
  2164. for (auto &cmd : commands)
  2165. {
  2166. if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None)
  2167. {
  2168. AddCompletionReply(chunk, cmd->Name());
  2169. }
  2170. }
  2171. } else if (pos)
  2172. {
  2173. if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
  2174. {
  2175. auto choices = pos->HelpChoices(helpParams);
  2176. hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
  2177. for (auto &choice : choices)
  2178. {
  2179. AddCompletionReply(chunk, choice);
  2180. }
  2181. }
  2182. }
  2183. if (hasPositionalCompletion)
  2184. {
  2185. auto flags = GetAllFlags();
  2186. for (auto flag : flags)
  2187. {
  2188. if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None)
  2189. {
  2190. continue;
  2191. }
  2192. auto &matcher = flag->GetMatcher();
  2193. if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix)))
  2194. {
  2195. for (auto &flagName : matcher.GetFlagStrings())
  2196. {
  2197. if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix)))
  2198. {
  2199. break;
  2200. }
  2201. }
  2202. }
  2203. }
  2204. if (optionType == OptionType::LongFlag && allowJoinedLongValue)
  2205. {
  2206. const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
  2207. if (separator != chunk.npos)
  2208. {
  2209. std::string arg(chunk, 0, separator);
  2210. if (auto flag = this->Match(arg.substr(longprefix.size())))
  2211. {
  2212. for (auto &choice : flag->HelpChoices(helpParams))
  2213. {
  2214. AddCompletionReply(chunk, arg + longseparator + choice);
  2215. }
  2216. }
  2217. }
  2218. } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
  2219. {
  2220. if (chunk.size() > shortprefix.size() + 1)
  2221. {
  2222. auto arg = chunk.at(shortprefix.size());
  2223. //TODO: support -abcVALUE where a and b take no value
  2224. if (auto flag = this->Match(arg))
  2225. {
  2226. for (auto &choice : flag->HelpChoices(helpParams))
  2227. {
  2228. AddCompletionReply(chunk, shortprefix + arg + choice);
  2229. }
  2230. }
  2231. }
  2232. }
  2233. }
  2234. }
  2235. #ifndef ARGS_NOEXCEPT
  2236. throw Completion(completion->Get());
  2237. #else
  2238. return true;
  2239. #endif
  2240. }
  2241. template <typename It>
  2242. It Parse(It begin, It end)
  2243. {
  2244. bool terminated = false;
  2245. std::vector<Command *> commands = GetCommands();
  2246. // Check all arg chunks
  2247. for (auto it = begin; it != end; ++it)
  2248. {
  2249. if (Complete(it, end))
  2250. {
  2251. return end;
  2252. }
  2253. const auto &chunk = *it;
  2254. if (!terminated && chunk == terminator)
  2255. {
  2256. terminated = true;
  2257. } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag)
  2258. {
  2259. if (!ParseLong(it, end))
  2260. {
  2261. return it;
  2262. }
  2263. } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag)
  2264. {
  2265. if (!ParseShort(it, end))
  2266. {
  2267. return it;
  2268. }
  2269. } else if (!terminated && !commands.empty())
  2270. {
  2271. auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; });
  2272. if (itCommand == commands.end())
  2273. {
  2274. const std::string errorMessage("Unknown command: " + chunk);
  2275. #ifndef ARGS_NOEXCEPT
  2276. throw ParseError(errorMessage);
  2277. #else
  2278. error = Error::Parse;
  2279. errorMsg = errorMessage;
  2280. return it;
  2281. #endif
  2282. }
  2283. SelectedCommand().SelectCommand(*itCommand);
  2284. if (const auto &coroutine = GetCoroutine())
  2285. {
  2286. ++it;
  2287. RaiiSubparser coro(*this, std::vector<std::string>(it, end));
  2288. coroutine(coro.Parser());
  2289. #ifdef ARGS_NOEXCEPT
  2290. error = GetError();
  2291. if (error != Error::None)
  2292. {
  2293. return end;
  2294. }
  2295. if (!coro.Parser().IsParsed())
  2296. {
  2297. error = Error::Usage;
  2298. return end;
  2299. }
  2300. #else
  2301. if (!coro.Parser().IsParsed())
  2302. {
  2303. throw UsageError("Subparser::Parse was not called");
  2304. }
  2305. #endif
  2306. break;
  2307. }
  2308. commands = GetCommands();
  2309. } else
  2310. {
  2311. auto pos = GetNextPositional();
  2312. if (pos)
  2313. {
  2314. pos->ParseValue(chunk);
  2315. if (pos->KickOut())
  2316. {
  2317. return ++it;
  2318. }
  2319. } else
  2320. {
  2321. const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk);
  2322. #ifndef ARGS_NOEXCEPT
  2323. throw ParseError(errorMessage);
  2324. #else
  2325. error = Error::Parse;
  2326. errorMsg = errorMessage;
  2327. return it;
  2328. #endif
  2329. }
  2330. }
  2331. if (!readCompletion && completion != nullptr && completion->Matched())
  2332. {
  2333. #ifdef ARGS_NOEXCEPT
  2334. error = Error::Completion;
  2335. #endif
  2336. readCompletion = true;
  2337. ++it;
  2338. const auto argsLeft = static_cast<size_t>(std::distance(it, end));
  2339. if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft)
  2340. {
  2341. #ifndef ARGS_NOEXCEPT
  2342. throw Completion("");
  2343. #endif
  2344. }
  2345. std::vector<std::string> curArgs(++it, end);
  2346. curArgs.resize(completion->cword);
  2347. if (completion->syntax == "bash")
  2348. {
  2349. // bash tokenizes --flag=value as --flag=value
  2350. for (size_t idx = 0; idx < curArgs.size(); )
  2351. {
  2352. if (idx > 0 && curArgs[idx] == "=")
  2353. {
  2354. curArgs[idx - 1] += "=";
  2355. // Avoid warnings from -Wsign-conversion
  2356. const auto signedIdx = static_cast<std::ptrdiff_t>(idx);
  2357. if (idx + 1 < curArgs.size())
  2358. {
  2359. curArgs[idx - 1] += curArgs[idx + 1];
  2360. curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2);
  2361. } else
  2362. {
  2363. curArgs.erase(curArgs.begin() + signedIdx);
  2364. }
  2365. } else
  2366. {
  2367. ++idx;
  2368. }
  2369. }
  2370. }
  2371. #ifndef ARGS_NOEXCEPT
  2372. try
  2373. {
  2374. Parse(curArgs.begin(), curArgs.end());
  2375. throw Completion("");
  2376. }
  2377. catch (Completion &)
  2378. {
  2379. throw;
  2380. }
  2381. catch (args::Error&)
  2382. {
  2383. throw Completion("");
  2384. }
  2385. #else
  2386. return Parse(curArgs.begin(), curArgs.end());
  2387. #endif
  2388. }
  2389. }
  2390. Validate(shortprefix, longprefix);
  2391. return end;
  2392. }
  2393. public:
  2394. HelpParams helpParams;
  2395. ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string())
  2396. {
  2397. Description(description_);
  2398. Epilog(epilog_);
  2399. LongPrefix("--");
  2400. ShortPrefix("-");
  2401. LongSeparator("=");
  2402. Terminator("--");
  2403. SetArgumentSeparations(true, true, true, true);
  2404. matched = true;
  2405. }
  2406. void AddCompletion(CompletionFlag &completionFlag)
  2407. {
  2408. completion = &completionFlag;
  2409. Add(completionFlag);
  2410. }
  2411. /** The program name for help generation
  2412. */
  2413. const std::string &Prog() const
  2414. { return helpParams.programName; }
  2415. /** The program name for help generation
  2416. */
  2417. void Prog(const std::string &prog_)
  2418. { this->helpParams.programName = prog_; }
  2419. /** The prefix for long flags
  2420. */
  2421. const std::string &LongPrefix() const
  2422. { return longprefix; }
  2423. /** The prefix for long flags
  2424. */
  2425. void LongPrefix(const std::string &longprefix_)
  2426. {
  2427. this->longprefix = longprefix_;
  2428. this->helpParams.longPrefix = longprefix_;
  2429. }
  2430. /** The prefix for short flags
  2431. */
  2432. const std::string &ShortPrefix() const
  2433. { return shortprefix; }
  2434. /** The prefix for short flags
  2435. */
  2436. void ShortPrefix(const std::string &shortprefix_)
  2437. {
  2438. this->shortprefix = shortprefix_;
  2439. this->helpParams.shortPrefix = shortprefix_;
  2440. }
  2441. /** The separator for long flags
  2442. */
  2443. const std::string &LongSeparator() const
  2444. { return longseparator; }
  2445. /** The separator for long flags
  2446. */
  2447. void LongSeparator(const std::string &longseparator_)
  2448. {
  2449. if (longseparator_.empty())
  2450. {
  2451. const std::string errorMessage("longseparator can not be set to empty");
  2452. #ifdef ARGS_NOEXCEPT
  2453. error = Error::Usage;
  2454. errorMsg = errorMessage;
  2455. #else
  2456. throw UsageError(errorMessage);
  2457. #endif
  2458. } else
  2459. {
  2460. this->longseparator = longseparator_;
  2461. this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " ";
  2462. }
  2463. }
  2464. /** The terminator that forcibly separates flags from positionals
  2465. */
  2466. const std::string &Terminator() const
  2467. { return terminator; }
  2468. /** The terminator that forcibly separates flags from positionals
  2469. */
  2470. void Terminator(const std::string &terminator_)
  2471. { this->terminator = terminator_; }
  2472. /** Get the current argument separation parameters.
  2473. *
  2474. * See SetArgumentSeparations for details on what each one means.
  2475. */
  2476. void GetArgumentSeparations(
  2477. bool &allowJoinedShortValue_,
  2478. bool &allowJoinedLongValue_,
  2479. bool &allowSeparateShortValue_,
  2480. bool &allowSeparateLongValue_) const
  2481. {
  2482. allowJoinedShortValue_ = this->allowJoinedShortValue;
  2483. allowJoinedLongValue_ = this->allowJoinedLongValue;
  2484. allowSeparateShortValue_ = this->allowSeparateShortValue;
  2485. allowSeparateLongValue_ = this->allowSeparateLongValue;
  2486. }
  2487. /** Change allowed option separation.
  2488. *
  2489. * \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)
  2490. * \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)
  2491. * \param allowSeparateShortValue_ Allow a short flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field)
  2492. * \param allowSeparateLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field)
  2493. */
  2494. void SetArgumentSeparations(
  2495. const bool allowJoinedShortValue_,
  2496. const bool allowJoinedLongValue_,
  2497. const bool allowSeparateShortValue_,
  2498. const bool allowSeparateLongValue_)
  2499. {
  2500. this->allowJoinedShortValue = allowJoinedShortValue_;
  2501. this->allowJoinedLongValue = allowJoinedLongValue_;
  2502. this->allowSeparateShortValue = allowSeparateShortValue_;
  2503. this->allowSeparateLongValue = allowSeparateLongValue_;
  2504. this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " ";
  2505. this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " ";
  2506. }
  2507. /** Pass the help menu into an ostream
  2508. */
  2509. void Help(std::ostream &help_) const
  2510. {
  2511. auto &command = SelectedCommand();
  2512. const auto &commandDescription = command.Description().empty() ? command.Help() : command.Description();
  2513. const auto description_text = Wrap(commandDescription, helpParams.width - helpParams.descriptionindent);
  2514. const auto epilog_text = Wrap(command.Epilog(), helpParams.width - helpParams.descriptionindent);
  2515. const bool hasoptions = command.HasFlag();
  2516. const bool hasarguments = command.HasPositional();
  2517. std::vector<std::string> prognameline;
  2518. prognameline.push_back(helpParams.usageString);
  2519. prognameline.push_back(Prog());
  2520. auto commandProgLine = command.GetProgramLine(helpParams);
  2521. prognameline.insert(prognameline.end(), commandProgLine.begin(), commandProgLine.end());
  2522. const auto proglines = Wrap(prognameline.begin(), prognameline.end(),
  2523. helpParams.width - (helpParams.progindent + helpParams.progtailindent),
  2524. helpParams.width - helpParams.progindent);
  2525. auto progit = std::begin(proglines);
  2526. if (progit != std::end(proglines))
  2527. {
  2528. help_ << std::string(helpParams.progindent, ' ') << *progit << '\n';
  2529. ++progit;
  2530. }
  2531. for (; progit != std::end(proglines); ++progit)
  2532. {
  2533. help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n';
  2534. }
  2535. help_ << '\n';
  2536. if (!description_text.empty())
  2537. {
  2538. for (const auto &line: description_text)
  2539. {
  2540. help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
  2541. }
  2542. help_ << "\n";
  2543. }
  2544. bool lastDescriptionIsNewline = false;
  2545. if (!helpParams.optionsString.empty())
  2546. {
  2547. help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n";
  2548. }
  2549. for (const auto &desc: command.GetDescription(helpParams, 0))
  2550. {
  2551. lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty();
  2552. const auto groupindent = std::get<2>(desc) * helpParams.eachgroupindent;
  2553. const auto flags = Wrap(std::get<0>(desc), helpParams.width - (helpParams.flagindent + helpParams.helpindent + helpParams.gutter));
  2554. const auto info = Wrap(std::get<1>(desc), helpParams.width - (helpParams.helpindent + groupindent));
  2555. std::string::size_type flagssize = 0;
  2556. for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit)
  2557. {
  2558. if (flagsit != std::begin(flags))
  2559. {
  2560. help_ << '\n';
  2561. }
  2562. help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit;
  2563. flagssize = Glyphs(*flagsit);
  2564. }
  2565. auto infoit = std::begin(info);
  2566. // groupindent is on both sides of this inequality, and therefore can be removed
  2567. if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription)
  2568. {
  2569. help_ << '\n';
  2570. } else
  2571. {
  2572. // groupindent is on both sides of the minus sign, and therefore doesn't actually need to be in here
  2573. help_ << std::string(helpParams.helpindent - (helpParams.flagindent + flagssize), ' ') << *infoit << '\n';
  2574. ++infoit;
  2575. }
  2576. for (; infoit != std::end(info); ++infoit)
  2577. {
  2578. help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n';
  2579. }
  2580. }
  2581. if (hasoptions && hasarguments && helpParams.showTerminator)
  2582. {
  2583. lastDescriptionIsNewline = false;
  2584. 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))
  2585. {
  2586. help_ << std::string(helpParams.flagindent, ' ') << item << '\n';
  2587. }
  2588. }
  2589. if (!lastDescriptionIsNewline)
  2590. {
  2591. help_ << "\n";
  2592. }
  2593. for (const auto &line: epilog_text)
  2594. {
  2595. help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n";
  2596. }
  2597. }
  2598. /** Generate a help menu as a string.
  2599. *
  2600. * \return the help text as a single string
  2601. */
  2602. std::string Help() const
  2603. {
  2604. std::ostringstream help_;
  2605. Help(help_);
  2606. return help_.str();
  2607. }
  2608. virtual void Reset() noexcept override
  2609. {
  2610. Command::Reset();
  2611. matched = true;
  2612. readCompletion = false;
  2613. }
  2614. /** Parse all arguments.
  2615. *
  2616. * \param begin an iterator to the beginning of the argument list
  2617. * \param end an iterator to the past-the-end element of the argument list
  2618. * \return the iterator after the last parsed value. Only useful for kick-out
  2619. */
  2620. template <typename It>
  2621. It ParseArgs(It begin, It end)
  2622. {
  2623. // Reset all Matched statuses and errors
  2624. Reset();
  2625. #ifdef ARGS_NOEXCEPT
  2626. error = GetError();
  2627. if (error != Error::None)
  2628. {
  2629. return end;
  2630. }
  2631. #endif
  2632. return Parse(begin, end);
  2633. }
  2634. /** Parse all arguments.
  2635. *
  2636. * \param args an iterable of the arguments
  2637. * \return the iterator after the last parsed value. Only useful for kick-out
  2638. */
  2639. template <typename T>
  2640. auto ParseArgs(const T &args) -> decltype(std::begin(args))
  2641. {
  2642. return ParseArgs(std::begin(args), std::end(args));
  2643. }
  2644. /** Convenience function to parse the CLI from argc and argv
  2645. *
  2646. * Just assigns the program name and vectorizes arguments for passing into ParseArgs()
  2647. *
  2648. * \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.
  2649. */
  2650. bool ParseCLI(const int argc, const char * const * argv)
  2651. {
  2652. if (Prog().empty())
  2653. {
  2654. Prog(argv[0]);
  2655. }
  2656. const std::vector<std::string> args(argv + 1, argv + argc);
  2657. return ParseArgs(args) == std::end(args);
  2658. }
  2659. template <typename T>
  2660. bool ParseCLI(const T &args)
  2661. {
  2662. return ParseArgs(args) == std::end(args);
  2663. }
  2664. };
  2665. inline Command::RaiiSubparser::RaiiSubparser(ArgumentParser &parser_, std::vector<std::string> args_)
  2666. : command(parser_.SelectedCommand()), parser(std::move(args_), parser_, command, parser_.helpParams), oldSubparser(command.subparser)
  2667. {
  2668. command.subparser = &parser;
  2669. }
  2670. inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams &params_): command(command_), parser(command, params_), oldSubparser(command.subparser)
  2671. {
  2672. command.subparser = &parser;
  2673. }
  2674. inline void Subparser::Parse()
  2675. {
  2676. isParsed = true;
  2677. Reset();
  2678. command.subparserDescription = GetDescription(helpParams, 0);
  2679. command.subparserHasFlag = HasFlag();
  2680. command.subparserHasPositional = HasPositional();
  2681. command.subparserHasCommand = HasCommand();
  2682. command.subparserProgramLine = GetProgramLine(helpParams);
  2683. if (parser == nullptr)
  2684. {
  2685. #ifndef ARGS_NOEXCEPT
  2686. throw args::SubparserError();
  2687. #else
  2688. error = Error::Subparser;
  2689. return;
  2690. #endif
  2691. }
  2692. auto it = parser->Parse(args.begin(), args.end());
  2693. command.Validate(parser->ShortPrefix(), parser->LongPrefix());
  2694. kicked.assign(it, args.end());
  2695. #ifdef ARGS_NOEXCEPT
  2696. command.subparserError = GetError();
  2697. #endif
  2698. }
  2699. inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser)
  2700. {
  2701. parser.Help(os);
  2702. return os;
  2703. }
  2704. /** Boolean argument matcher
  2705. */
  2706. class Flag : public FlagBase
  2707. {
  2708. public:
  2709. Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_)
  2710. {
  2711. group_.Add(*this);
  2712. }
  2713. 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)
  2714. {
  2715. }
  2716. virtual ~Flag() {}
  2717. /** Get whether this was matched
  2718. */
  2719. bool Get() const
  2720. {
  2721. return Matched();
  2722. }
  2723. virtual Nargs NumberOfArguments() const noexcept override
  2724. {
  2725. return 0;
  2726. }
  2727. virtual void ParseValue(const std::vector<std::string>&) override
  2728. {
  2729. }
  2730. };
  2731. /** Help flag class
  2732. *
  2733. * Works like a regular flag, but throws an instance of Help when it is matched
  2734. */
  2735. class HelpFlag : public Flag
  2736. {
  2737. public:
  2738. HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {}
  2739. virtual ~HelpFlag() {}
  2740. virtual void ParseValue(const std::vector<std::string> &)
  2741. {
  2742. #ifdef ARGS_NOEXCEPT
  2743. error = Error::Help;
  2744. errorMsg = Name();
  2745. #else
  2746. throw Help(Name());
  2747. #endif
  2748. }
  2749. /** Get whether this was matched
  2750. */
  2751. bool Get() const noexcept
  2752. {
  2753. return Matched();
  2754. }
  2755. };
  2756. /** A flag class that simply counts the number of times it's matched
  2757. */
  2758. class CounterFlag : public Flag
  2759. {
  2760. private:
  2761. const int startcount;
  2762. int count;
  2763. public:
  2764. CounterFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const int startcount_ = 0, Options options_ = {}):
  2765. Flag(group_, name_, help_, std::move(matcher_), options_), startcount(startcount_), count(startcount_) {}
  2766. virtual ~CounterFlag() {}
  2767. virtual FlagBase *Match(const EitherFlag &arg) override
  2768. {
  2769. auto me = FlagBase::Match(arg);
  2770. if (me)
  2771. {
  2772. ++count;
  2773. }
  2774. return me;
  2775. }
  2776. /** Get the count
  2777. */
  2778. int &Get() noexcept
  2779. {
  2780. return count;
  2781. }
  2782. virtual void Reset() noexcept override
  2783. {
  2784. FlagBase::Reset();
  2785. count = startcount;
  2786. }
  2787. };
  2788. /** A flag class that calls a function when it's matched
  2789. */
  2790. class ActionFlag : public FlagBase
  2791. {
  2792. private:
  2793. std::function<void(const std::vector<std::string> &)> action;
  2794. Nargs nargs;
  2795. public:
  2796. 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_ = {}):
  2797. FlagBase(name_, help_, std::move(matcher_), options_), action(std::move(action_)), nargs(nargs_)
  2798. {
  2799. group_.Add(*this);
  2800. }
  2801. ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void(const std::string &)> action_, Options options_ = {}):
  2802. FlagBase(name_, help_, std::move(matcher_), options_), nargs(1)
  2803. {
  2804. group_.Add(*this);
  2805. action = [action_](const std::vector<std::string> &a) { return action_(a.at(0)); };
  2806. }
  2807. ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function<void()> action_, Options options_ = {}):
  2808. FlagBase(name_, help_, std::move(matcher_), options_), nargs(0)
  2809. {
  2810. group_.Add(*this);
  2811. action = [action_](const std::vector<std::string> &) { return action_(); };
  2812. }
  2813. virtual Nargs NumberOfArguments() const noexcept override
  2814. { return nargs; }
  2815. virtual void ParseValue(const std::vector<std::string> &value) override
  2816. { action(value); }
  2817. };
  2818. /** A default Reader class for argument classes
  2819. *
  2820. * If destination type is assignable to std::string it uses an assignment to std::string.
  2821. * Otherwise ValueReader simply uses a std::istringstream to read into the destination type, and
  2822. * raises a ParseError if there are any characters left.
  2823. */
  2824. struct ValueReader
  2825. {
  2826. template <typename T>
  2827. typename std::enable_if<!std::is_assignable<T, std::string>::value, bool>::type
  2828. operator ()(const std::string &name, const std::string &value, T &destination)
  2829. {
  2830. std::istringstream ss(value);
  2831. bool failed = !(ss >> destination);
  2832. if (!failed)
  2833. {
  2834. ss >> std::ws;
  2835. }
  2836. if (ss.rdbuf()->in_avail() > 0 || failed)
  2837. {
  2838. #ifdef ARGS_NOEXCEPT
  2839. (void)name;
  2840. return false;
  2841. #else
  2842. std::ostringstream problem;
  2843. problem << "Argument '" << name << "' received invalid value type '" << value << "'";
  2844. throw ParseError(problem.str());
  2845. #endif
  2846. }
  2847. return true;
  2848. }
  2849. template <typename T>
  2850. typename std::enable_if<std::is_assignable<T, std::string>::value, bool>::type
  2851. operator()(const std::string &, const std::string &value, T &destination)
  2852. {
  2853. destination = value;
  2854. return true;
  2855. }
  2856. };
  2857. /** An argument-accepting flag class
  2858. *
  2859. * \tparam T the type to extract the argument as
  2860. * \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)
  2861. */
  2862. template <
  2863. typename T,
  2864. typename Reader = ValueReader>
  2865. class ValueFlag : public ValueFlagBase
  2866. {
  2867. protected:
  2868. T value;
  2869. T defaultValue;
  2870. virtual std::string GetDefaultString(const HelpParams&) const override
  2871. {
  2872. return detail::ToString(defaultValue);
  2873. }
  2874. private:
  2875. Reader reader;
  2876. public:
  2877. 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_)
  2878. {
  2879. group_.Add(*this);
  2880. }
  2881. 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)
  2882. {
  2883. }
  2884. ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): ValueFlag(group_, name_, help_, std::move(matcher_), T(), options_)
  2885. {
  2886. }
  2887. virtual ~ValueFlag() {}
  2888. virtual void ParseValue(const std::vector<std::string> &values_) override
  2889. {
  2890. const std::string &value_ = values_.at(0);
  2891. #ifdef ARGS_NOEXCEPT
  2892. if (!reader(name, value_, this->value))
  2893. {
  2894. error = Error::Parse;
  2895. }
  2896. #else
  2897. reader(name, value_, this->value);
  2898. #endif
  2899. }
  2900. virtual void Reset() noexcept override
  2901. {
  2902. ValueFlagBase::Reset();
  2903. value = defaultValue;
  2904. }
  2905. /** Get the value
  2906. */
  2907. T &Get() noexcept
  2908. {
  2909. return value;
  2910. }
  2911. /** Get the default value
  2912. */
  2913. const T &GetDefault() noexcept
  2914. {
  2915. return defaultValue;
  2916. }
  2917. };
  2918. /** An optional argument-accepting flag class
  2919. *
  2920. * \tparam T the type to extract the argument as
  2921. * \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)
  2922. */
  2923. template <
  2924. typename T,
  2925. typename Reader = ValueReader>
  2926. class ImplicitValueFlag : public ValueFlag<T, Reader>
  2927. {
  2928. protected:
  2929. T implicitValue;
  2930. public:
  2931. ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {})
  2932. : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_)
  2933. {
  2934. }
  2935. ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {})
  2936. : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_)
  2937. {
  2938. }
  2939. ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_)
  2940. : ValueFlag<T, Reader>(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue()
  2941. {
  2942. }
  2943. virtual ~ImplicitValueFlag() {}
  2944. virtual Nargs NumberOfArguments() const noexcept override
  2945. {
  2946. return {0, 1};
  2947. }
  2948. virtual void ParseValue(const std::vector<std::string> &value_) override
  2949. {
  2950. if (value_.empty())
  2951. {
  2952. this->value = implicitValue;
  2953. } else
  2954. {
  2955. ValueFlag<T, Reader>::ParseValue(value_);
  2956. }
  2957. }
  2958. };
  2959. /** A variadic arguments accepting flag class
  2960. *
  2961. * \tparam T the type to extract the argument as
  2962. * \tparam List the list type that houses the values
  2963. * \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)
  2964. */
  2965. template <
  2966. typename T,
  2967. template <typename...> class List = std::vector,
  2968. typename Reader = ValueReader>
  2969. class NargsValueFlag : public FlagBase
  2970. {
  2971. protected:
  2972. List<T> values;
  2973. const List<T> defaultValues;
  2974. Nargs nargs;
  2975. Reader reader;
  2976. public:
  2977. typedef List<T> Container;
  2978. typedef T value_type;
  2979. typedef typename Container::allocator_type allocator_type;
  2980. typedef typename Container::pointer pointer;
  2981. typedef typename Container::const_pointer const_pointer;
  2982. typedef T& reference;
  2983. typedef const T& const_reference;
  2984. typedef typename Container::size_type size_type;
  2985. typedef typename Container::difference_type difference_type;
  2986. typedef typename Container::iterator iterator;
  2987. typedef typename Container::const_iterator const_iterator;
  2988. typedef std::reverse_iterator<iterator> reverse_iterator;
  2989. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  2990. NargsValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, const List<T> &defaultValues_ = {}, Options options_ = {})
  2991. : FlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_),nargs(nargs_)
  2992. {
  2993. group_.Add(*this);
  2994. }
  2995. virtual ~NargsValueFlag() {}
  2996. virtual Nargs NumberOfArguments() const noexcept override
  2997. {
  2998. return nargs;
  2999. }
  3000. virtual void ParseValue(const std::vector<std::string> &values_) override
  3001. {
  3002. values.clear();
  3003. for (const std::string &value : values_)
  3004. {
  3005. T v;
  3006. #ifdef ARGS_NOEXCEPT
  3007. if (!reader(name, value, v))
  3008. {
  3009. error = Error::Parse;
  3010. }
  3011. #else
  3012. reader(name, value, v);
  3013. #endif
  3014. values.insert(std::end(values), v);
  3015. }
  3016. }
  3017. List<T> &Get() noexcept
  3018. {
  3019. return values;
  3020. }
  3021. iterator begin() noexcept
  3022. {
  3023. return values.begin();
  3024. }
  3025. const_iterator begin() const noexcept
  3026. {
  3027. return values.begin();
  3028. }
  3029. const_iterator cbegin() const noexcept
  3030. {
  3031. return values.cbegin();
  3032. }
  3033. iterator end() noexcept
  3034. {
  3035. return values.end();
  3036. }
  3037. const_iterator end() const noexcept
  3038. {
  3039. return values.end();
  3040. }
  3041. const_iterator cend() const noexcept
  3042. {
  3043. return values.cend();
  3044. }
  3045. virtual void Reset() noexcept override
  3046. {
  3047. FlagBase::Reset();
  3048. values = defaultValues;
  3049. }
  3050. virtual FlagBase *Match(const EitherFlag &arg) override
  3051. {
  3052. const bool wasMatched = Matched();
  3053. auto me = FlagBase::Match(arg);
  3054. if (me && !wasMatched)
  3055. {
  3056. values.clear();
  3057. }
  3058. return me;
  3059. }
  3060. };
  3061. /** An argument-accepting flag class that pushes the found values into a list
  3062. *
  3063. * \tparam T the type to extract the argument as
  3064. * \tparam List the list type that houses the values
  3065. * \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)
  3066. */
  3067. template <
  3068. typename T,
  3069. template <typename...> class List = std::vector,
  3070. typename Reader = ValueReader>
  3071. class ValueFlagList : public ValueFlagBase
  3072. {
  3073. private:
  3074. using Container = List<T>;
  3075. Container values;
  3076. const Container defaultValues;
  3077. Reader reader;
  3078. public:
  3079. typedef T value_type;
  3080. typedef typename Container::allocator_type allocator_type;
  3081. typedef typename Container::pointer pointer;
  3082. typedef typename Container::const_pointer const_pointer;
  3083. typedef T& reference;
  3084. typedef const T& const_reference;
  3085. typedef typename Container::size_type size_type;
  3086. typedef typename Container::difference_type difference_type;
  3087. typedef typename Container::iterator iterator;
  3088. typedef typename Container::const_iterator const_iterator;
  3089. typedef std::reverse_iterator<iterator> reverse_iterator;
  3090. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  3091. ValueFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Container &defaultValues_ = Container(), Options options_ = {}):
  3092. ValueFlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_)
  3093. {
  3094. group_.Add(*this);
  3095. }
  3096. virtual ~ValueFlagList() {}
  3097. virtual void ParseValue(const std::vector<std::string> &values_) override
  3098. {
  3099. const std::string &value_ = values_.at(0);
  3100. T v;
  3101. #ifdef ARGS_NOEXCEPT
  3102. if (!reader(name, value_, v))
  3103. {
  3104. error = Error::Parse;
  3105. }
  3106. #else
  3107. reader(name, value_, v);
  3108. #endif
  3109. values.insert(std::end(values), v);
  3110. }
  3111. /** Get the values
  3112. */
  3113. Container &Get() noexcept
  3114. {
  3115. return values;
  3116. }
  3117. virtual std::string Name() const override
  3118. {
  3119. return name + std::string("...");
  3120. }
  3121. virtual void Reset() noexcept override
  3122. {
  3123. ValueFlagBase::Reset();
  3124. values = defaultValues;
  3125. }
  3126. virtual FlagBase *Match(const EitherFlag &arg) override
  3127. {
  3128. const bool wasMatched = Matched();
  3129. auto me = FlagBase::Match(arg);
  3130. if (me && !wasMatched)
  3131. {
  3132. values.clear();
  3133. }
  3134. return me;
  3135. }
  3136. iterator begin() noexcept
  3137. {
  3138. return values.begin();
  3139. }
  3140. const_iterator begin() const noexcept
  3141. {
  3142. return values.begin();
  3143. }
  3144. const_iterator cbegin() const noexcept
  3145. {
  3146. return values.cbegin();
  3147. }
  3148. iterator end() noexcept
  3149. {
  3150. return values.end();
  3151. }
  3152. const_iterator end() const noexcept
  3153. {
  3154. return values.end();
  3155. }
  3156. const_iterator cend() const noexcept
  3157. {
  3158. return values.cend();
  3159. }
  3160. };
  3161. /** A mapping value flag class
  3162. *
  3163. * \tparam K the type to extract the argument as
  3164. * \tparam T the type to store the result as
  3165. * \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)
  3166. * \tparam Map The Map type. Should operate like std::map or std::unordered_map
  3167. */
  3168. template <
  3169. typename K,
  3170. typename T,
  3171. typename Reader = ValueReader,
  3172. template <typename...> class Map = std::unordered_map>
  3173. class MapFlag : public ValueFlagBase
  3174. {
  3175. private:
  3176. const Map<K, T> map;
  3177. T value;
  3178. const T defaultValue;
  3179. Reader reader;
  3180. protected:
  3181. virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
  3182. {
  3183. return detail::MapKeysToStrings(map);
  3184. }
  3185. public:
  3186. 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_)
  3187. {
  3188. group_.Add(*this);
  3189. }
  3190. 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)
  3191. {
  3192. }
  3193. 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_)
  3194. {
  3195. }
  3196. virtual ~MapFlag() {}
  3197. virtual void ParseValue(const std::vector<std::string> &values_) override
  3198. {
  3199. const std::string &value_ = values_.at(0);
  3200. K key;
  3201. #ifdef ARGS_NOEXCEPT
  3202. if (!reader(name, value_, key))
  3203. {
  3204. error = Error::Parse;
  3205. }
  3206. #else
  3207. reader(name, value_, key);
  3208. #endif
  3209. auto it = map.find(key);
  3210. if (it == std::end(map))
  3211. {
  3212. std::ostringstream problem;
  3213. problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
  3214. #ifdef ARGS_NOEXCEPT
  3215. error = Error::Map;
  3216. errorMsg = problem.str();
  3217. #else
  3218. throw MapError(problem.str());
  3219. #endif
  3220. } else
  3221. {
  3222. this->value = it->second;
  3223. }
  3224. }
  3225. /** Get the value
  3226. */
  3227. T &Get() noexcept
  3228. {
  3229. return value;
  3230. }
  3231. virtual void Reset() noexcept override
  3232. {
  3233. ValueFlagBase::Reset();
  3234. value = defaultValue;
  3235. }
  3236. };
  3237. /** A mapping value flag list class
  3238. *
  3239. * \tparam K the type to extract the argument as
  3240. * \tparam T the type to store the result as
  3241. * \tparam List the list type that houses the values
  3242. * \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)
  3243. * \tparam Map The Map type. Should operate like std::map or std::unordered_map
  3244. */
  3245. template <
  3246. typename K,
  3247. typename T,
  3248. template <typename...> class List = std::vector,
  3249. typename Reader = ValueReader,
  3250. template <typename...> class Map = std::unordered_map>
  3251. class MapFlagList : public ValueFlagBase
  3252. {
  3253. private:
  3254. using Container = List<T>;
  3255. const Map<K, T> map;
  3256. Container values;
  3257. const Container defaultValues;
  3258. Reader reader;
  3259. protected:
  3260. virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
  3261. {
  3262. return detail::MapKeysToStrings(map);
  3263. }
  3264. public:
  3265. typedef T value_type;
  3266. typedef typename Container::allocator_type allocator_type;
  3267. typedef typename Container::pointer pointer;
  3268. typedef typename Container::const_pointer const_pointer;
  3269. typedef T& reference;
  3270. typedef const T& const_reference;
  3271. typedef typename Container::size_type size_type;
  3272. typedef typename Container::difference_type difference_type;
  3273. typedef typename Container::iterator iterator;
  3274. typedef typename Container::const_iterator const_iterator;
  3275. typedef std::reverse_iterator<iterator> reverse_iterator;
  3276. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  3277. 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_)
  3278. {
  3279. group_.Add(*this);
  3280. }
  3281. virtual ~MapFlagList() {}
  3282. virtual void ParseValue(const std::vector<std::string> &values_) override
  3283. {
  3284. const std::string &value = values_.at(0);
  3285. K key;
  3286. #ifdef ARGS_NOEXCEPT
  3287. if (!reader(name, value, key))
  3288. {
  3289. error = Error::Parse;
  3290. }
  3291. #else
  3292. reader(name, value, key);
  3293. #endif
  3294. auto it = map.find(key);
  3295. if (it == std::end(map))
  3296. {
  3297. std::ostringstream problem;
  3298. problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
  3299. #ifdef ARGS_NOEXCEPT
  3300. error = Error::Map;
  3301. errorMsg = problem.str();
  3302. #else
  3303. throw MapError(problem.str());
  3304. #endif
  3305. } else
  3306. {
  3307. this->values.emplace_back(it->second);
  3308. }
  3309. }
  3310. /** Get the value
  3311. */
  3312. Container &Get() noexcept
  3313. {
  3314. return values;
  3315. }
  3316. virtual std::string Name() const override
  3317. {
  3318. return name + std::string("...");
  3319. }
  3320. virtual void Reset() noexcept override
  3321. {
  3322. ValueFlagBase::Reset();
  3323. values = defaultValues;
  3324. }
  3325. virtual FlagBase *Match(const EitherFlag &arg) override
  3326. {
  3327. const bool wasMatched = Matched();
  3328. auto me = FlagBase::Match(arg);
  3329. if (me && !wasMatched)
  3330. {
  3331. values.clear();
  3332. }
  3333. return me;
  3334. }
  3335. iterator begin() noexcept
  3336. {
  3337. return values.begin();
  3338. }
  3339. const_iterator begin() const noexcept
  3340. {
  3341. return values.begin();
  3342. }
  3343. const_iterator cbegin() const noexcept
  3344. {
  3345. return values.cbegin();
  3346. }
  3347. iterator end() noexcept
  3348. {
  3349. return values.end();
  3350. }
  3351. const_iterator end() const noexcept
  3352. {
  3353. return values.end();
  3354. }
  3355. const_iterator cend() const noexcept
  3356. {
  3357. return values.cend();
  3358. }
  3359. };
  3360. /** A positional argument class
  3361. *
  3362. * \tparam T the type to extract the argument as
  3363. * \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)
  3364. */
  3365. template <
  3366. typename T,
  3367. typename Reader = ValueReader>
  3368. class Positional : public PositionalBase
  3369. {
  3370. private:
  3371. T value;
  3372. const T defaultValue;
  3373. Reader reader;
  3374. public:
  3375. 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_)
  3376. {
  3377. group_.Add(*this);
  3378. }
  3379. Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_)
  3380. {
  3381. }
  3382. virtual ~Positional() {}
  3383. virtual void ParseValue(const std::string &value_) override
  3384. {
  3385. #ifdef ARGS_NOEXCEPT
  3386. if (!reader(name, value_, this->value))
  3387. {
  3388. error = Error::Parse;
  3389. }
  3390. #else
  3391. reader(name, value_, this->value);
  3392. #endif
  3393. ready = false;
  3394. matched = true;
  3395. }
  3396. /** Get the value
  3397. */
  3398. T &Get() noexcept
  3399. {
  3400. return value;
  3401. }
  3402. virtual void Reset() noexcept override
  3403. {
  3404. PositionalBase::Reset();
  3405. value = defaultValue;
  3406. }
  3407. };
  3408. /** A positional argument class that pushes the found values into a list
  3409. *
  3410. * \tparam T the type to extract the argument as
  3411. * \tparam List the list type that houses the values
  3412. * \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)
  3413. */
  3414. template <
  3415. typename T,
  3416. template <typename...> class List = std::vector,
  3417. typename Reader = ValueReader>
  3418. class PositionalList : public PositionalBase
  3419. {
  3420. private:
  3421. using Container = List<T>;
  3422. Container values;
  3423. const Container defaultValues;
  3424. Reader reader;
  3425. public:
  3426. typedef T value_type;
  3427. typedef typename Container::allocator_type allocator_type;
  3428. typedef typename Container::pointer pointer;
  3429. typedef typename Container::const_pointer const_pointer;
  3430. typedef T& reference;
  3431. typedef const T& const_reference;
  3432. typedef typename Container::size_type size_type;
  3433. typedef typename Container::difference_type difference_type;
  3434. typedef typename Container::iterator iterator;
  3435. typedef typename Container::const_iterator const_iterator;
  3436. typedef std::reverse_iterator<iterator> reverse_iterator;
  3437. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  3438. 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_)
  3439. {
  3440. group_.Add(*this);
  3441. }
  3442. PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_)
  3443. {
  3444. }
  3445. virtual ~PositionalList() {}
  3446. virtual void ParseValue(const std::string &value_) override
  3447. {
  3448. T v;
  3449. #ifdef ARGS_NOEXCEPT
  3450. if (!reader(name, value_, v))
  3451. {
  3452. error = Error::Parse;
  3453. }
  3454. #else
  3455. reader(name, value_, v);
  3456. #endif
  3457. values.insert(std::end(values), v);
  3458. matched = true;
  3459. }
  3460. virtual std::string Name() const override
  3461. {
  3462. return name + std::string("...");
  3463. }
  3464. /** Get the values
  3465. */
  3466. Container &Get() noexcept
  3467. {
  3468. return values;
  3469. }
  3470. virtual void Reset() noexcept override
  3471. {
  3472. PositionalBase::Reset();
  3473. values = defaultValues;
  3474. }
  3475. virtual PositionalBase *GetNextPositional() override
  3476. {
  3477. const bool wasMatched = Matched();
  3478. auto me = PositionalBase::GetNextPositional();
  3479. if (me && !wasMatched)
  3480. {
  3481. values.clear();
  3482. }
  3483. return me;
  3484. }
  3485. iterator begin() noexcept
  3486. {
  3487. return values.begin();
  3488. }
  3489. const_iterator begin() const noexcept
  3490. {
  3491. return values.begin();
  3492. }
  3493. const_iterator cbegin() const noexcept
  3494. {
  3495. return values.cbegin();
  3496. }
  3497. iterator end() noexcept
  3498. {
  3499. return values.end();
  3500. }
  3501. const_iterator end() const noexcept
  3502. {
  3503. return values.end();
  3504. }
  3505. const_iterator cend() const noexcept
  3506. {
  3507. return values.cend();
  3508. }
  3509. };
  3510. /** A positional argument mapping class
  3511. *
  3512. * \tparam K the type to extract the argument as
  3513. * \tparam T the type to store the result as
  3514. * \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)
  3515. * \tparam Map The Map type. Should operate like std::map or std::unordered_map
  3516. */
  3517. template <
  3518. typename K,
  3519. typename T,
  3520. typename Reader = ValueReader,
  3521. template <typename...> class Map = std::unordered_map>
  3522. class MapPositional : public PositionalBase
  3523. {
  3524. private:
  3525. const Map<K, T> map;
  3526. T value;
  3527. const T defaultValue;
  3528. Reader reader;
  3529. protected:
  3530. virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
  3531. {
  3532. return detail::MapKeysToStrings(map);
  3533. }
  3534. public:
  3535. MapPositional(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const T &defaultValue_ = T(), Options options_ = {}):
  3536. PositionalBase(name_, help_, options_), map(map_), value(defaultValue_), defaultValue(defaultValue_)
  3537. {
  3538. group_.Add(*this);
  3539. }
  3540. virtual ~MapPositional() {}
  3541. virtual void ParseValue(const std::string &value_) override
  3542. {
  3543. K key;
  3544. #ifdef ARGS_NOEXCEPT
  3545. if (!reader(name, value_, key))
  3546. {
  3547. error = Error::Parse;
  3548. }
  3549. #else
  3550. reader(name, value_, key);
  3551. #endif
  3552. auto it = map.find(key);
  3553. if (it == std::end(map))
  3554. {
  3555. std::ostringstream problem;
  3556. problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
  3557. #ifdef ARGS_NOEXCEPT
  3558. error = Error::Map;
  3559. errorMsg = problem.str();
  3560. #else
  3561. throw MapError(problem.str());
  3562. #endif
  3563. } else
  3564. {
  3565. this->value = it->second;
  3566. ready = false;
  3567. matched = true;
  3568. }
  3569. }
  3570. /** Get the value
  3571. */
  3572. T &Get() noexcept
  3573. {
  3574. return value;
  3575. }
  3576. virtual void Reset() noexcept override
  3577. {
  3578. PositionalBase::Reset();
  3579. value = defaultValue;
  3580. }
  3581. };
  3582. /** A positional argument mapping list class
  3583. *
  3584. * \tparam K the type to extract the argument as
  3585. * \tparam T the type to store the result as
  3586. * \tparam List the list type that houses the values
  3587. * \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)
  3588. * \tparam Map The Map type. Should operate like std::map or std::unordered_map
  3589. */
  3590. template <
  3591. typename K,
  3592. typename T,
  3593. template <typename...> class List = std::vector,
  3594. typename Reader = ValueReader,
  3595. template <typename...> class Map = std::unordered_map>
  3596. class MapPositionalList : public PositionalBase
  3597. {
  3598. private:
  3599. using Container = List<T>;
  3600. const Map<K, T> map;
  3601. Container values;
  3602. const Container defaultValues;
  3603. Reader reader;
  3604. protected:
  3605. virtual std::vector<std::string> GetChoicesStrings(const HelpParams &) const override
  3606. {
  3607. return detail::MapKeysToStrings(map);
  3608. }
  3609. public:
  3610. typedef T value_type;
  3611. typedef typename Container::allocator_type allocator_type;
  3612. typedef typename Container::pointer pointer;
  3613. typedef typename Container::const_pointer const_pointer;
  3614. typedef T& reference;
  3615. typedef const T& const_reference;
  3616. typedef typename Container::size_type size_type;
  3617. typedef typename Container::difference_type difference_type;
  3618. typedef typename Container::iterator iterator;
  3619. typedef typename Container::const_iterator const_iterator;
  3620. typedef std::reverse_iterator<iterator> reverse_iterator;
  3621. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  3622. MapPositionalList(Group &group_, const std::string &name_, const std::string &help_, const Map<K, T> &map_, const Container &defaultValues_ = Container(), Options options_ = {}):
  3623. PositionalBase(name_, help_, options_), map(map_), values(defaultValues_), defaultValues(defaultValues_)
  3624. {
  3625. group_.Add(*this);
  3626. }
  3627. virtual ~MapPositionalList() {}
  3628. virtual void ParseValue(const std::string &value_) override
  3629. {
  3630. K key;
  3631. #ifdef ARGS_NOEXCEPT
  3632. if (!reader(name, value_, key))
  3633. {
  3634. error = Error::Parse;
  3635. }
  3636. #else
  3637. reader(name, value_, key);
  3638. #endif
  3639. auto it = map.find(key);
  3640. if (it == std::end(map))
  3641. {
  3642. std::ostringstream problem;
  3643. problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
  3644. #ifdef ARGS_NOEXCEPT
  3645. error = Error::Map;
  3646. errorMsg = problem.str();
  3647. #else
  3648. throw MapError(problem.str());
  3649. #endif
  3650. } else
  3651. {
  3652. this->values.emplace_back(it->second);
  3653. matched = true;
  3654. }
  3655. }
  3656. /** Get the value
  3657. */
  3658. Container &Get() noexcept
  3659. {
  3660. return values;
  3661. }
  3662. virtual std::string Name() const override
  3663. {
  3664. return name + std::string("...");
  3665. }
  3666. virtual void Reset() noexcept override
  3667. {
  3668. PositionalBase::Reset();
  3669. values = defaultValues;
  3670. }
  3671. virtual PositionalBase *GetNextPositional() override
  3672. {
  3673. const bool wasMatched = Matched();
  3674. auto me = PositionalBase::GetNextPositional();
  3675. if (me && !wasMatched)
  3676. {
  3677. values.clear();
  3678. }
  3679. return me;
  3680. }
  3681. iterator begin() noexcept
  3682. {
  3683. return values.begin();
  3684. }
  3685. const_iterator begin() const noexcept
  3686. {
  3687. return values.begin();
  3688. }
  3689. const_iterator cbegin() const noexcept
  3690. {
  3691. return values.cbegin();
  3692. }
  3693. iterator end() noexcept
  3694. {
  3695. return values.end();
  3696. }
  3697. const_iterator end() const noexcept
  3698. {
  3699. return values.end();
  3700. }
  3701. const_iterator cend() const noexcept
  3702. {
  3703. return values.cend();
  3704. }
  3705. };
  3706. }
  3707. #endif