Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

4261 Zeilen
141KB

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