🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2231 lines
45 KiB

  1. /*
  2. Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #ifndef CXXOPTS_HPP_INCLUDED
  20. #define CXXOPTS_HPP_INCLUDED
  21. #include <cctype>
  22. #include <cstring>
  23. #include <exception>
  24. #include <iostream>
  25. #include <limits>
  26. #include <map>
  27. #include <memory>
  28. #include <regex>
  29. #include <sstream>
  30. #include <string>
  31. #include <unordered_map>
  32. #include <unordered_set>
  33. #include <utility>
  34. #include <vector>
  35. #ifdef __cpp_lib_optional
  36. #include <optional>
  37. #define CXXOPTS_HAS_OPTIONAL
  38. #endif
  39. #if __cplusplus >= 201603L
  40. #define CXXOPTS_NODISCARD [[nodiscard]]
  41. #else
  42. #define CXXOPTS_NODISCARD
  43. #endif
  44. #ifndef CXXOPTS_VECTOR_DELIMITER
  45. #define CXXOPTS_VECTOR_DELIMITER ','
  46. #endif
  47. #define CXXOPTS__VERSION_MAJOR 2
  48. #define CXXOPTS__VERSION_MINOR 2
  49. #define CXXOPTS__VERSION_PATCH 0
  50. namespace cxxopts
  51. {
  52. static constexpr struct {
  53. uint8_t major, minor, patch;
  54. } version = {
  55. CXXOPTS__VERSION_MAJOR,
  56. CXXOPTS__VERSION_MINOR,
  57. CXXOPTS__VERSION_PATCH
  58. };
  59. } // namespace cxxopts
  60. //when we ask cxxopts to use Unicode, help strings are processed using ICU,
  61. //which results in the correct lengths being computed for strings when they
  62. //are formatted for the help output
  63. //it is necessary to make sure that <unicode/unistr.h> can be found by the
  64. //compiler, and that icu-uc is linked in to the binary.
  65. #ifdef CXXOPTS_USE_UNICODE
  66. #include <unicode/unistr.h>
  67. namespace cxxopts
  68. {
  69. typedef icu::UnicodeString String;
  70. inline
  71. String
  72. toLocalString(std::string s)
  73. {
  74. return icu::UnicodeString::fromUTF8(std::move(s));
  75. }
  76. class UnicodeStringIterator : public
  77. std::iterator<std::forward_iterator_tag, int32_t>
  78. {
  79. public:
  80. UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
  81. : s(string)
  82. , i(pos)
  83. {
  84. }
  85. value_type
  86. operator*() const
  87. {
  88. return s->char32At(i);
  89. }
  90. bool
  91. operator==(const UnicodeStringIterator& rhs) const
  92. {
  93. return s == rhs.s && i == rhs.i;
  94. }
  95. bool
  96. operator!=(const UnicodeStringIterator& rhs) const
  97. {
  98. return !(*this == rhs);
  99. }
  100. UnicodeStringIterator&
  101. operator++()
  102. {
  103. ++i;
  104. return *this;
  105. }
  106. UnicodeStringIterator
  107. operator+(int32_t v)
  108. {
  109. return UnicodeStringIterator(s, i + v);
  110. }
  111. private:
  112. const icu::UnicodeString* s;
  113. int32_t i;
  114. };
  115. inline
  116. String&
  117. stringAppend(String&s, String a)
  118. {
  119. return s.append(std::move(a));
  120. }
  121. inline
  122. String&
  123. stringAppend(String& s, int n, UChar32 c)
  124. {
  125. for (int i = 0; i != n; ++i)
  126. {
  127. s.append(c);
  128. }
  129. return s;
  130. }
  131. template <typename Iterator>
  132. String&
  133. stringAppend(String& s, Iterator begin, Iterator end)
  134. {
  135. while (begin != end)
  136. {
  137. s.append(*begin);
  138. ++begin;
  139. }
  140. return s;
  141. }
  142. inline
  143. size_t
  144. stringLength(const String& s)
  145. {
  146. return s.length();
  147. }
  148. inline
  149. std::string
  150. toUTF8String(const String& s)
  151. {
  152. std::string result;
  153. s.toUTF8String(result);
  154. return result;
  155. }
  156. inline
  157. bool
  158. empty(const String& s)
  159. {
  160. return s.isEmpty();
  161. }
  162. }
  163. namespace std
  164. {
  165. inline
  166. cxxopts::UnicodeStringIterator
  167. begin(const icu::UnicodeString& s)
  168. {
  169. return cxxopts::UnicodeStringIterator(&s, 0);
  170. }
  171. inline
  172. cxxopts::UnicodeStringIterator
  173. end(const icu::UnicodeString& s)
  174. {
  175. return cxxopts::UnicodeStringIterator(&s, s.length());
  176. }
  177. }
  178. //ifdef CXXOPTS_USE_UNICODE
  179. #else
  180. namespace cxxopts
  181. {
  182. typedef std::string String;
  183. template <typename T>
  184. T
  185. toLocalString(T&& t)
  186. {
  187. return std::forward<T>(t);
  188. }
  189. inline
  190. size_t
  191. stringLength(const String& s)
  192. {
  193. return s.length();
  194. }
  195. inline
  196. String&
  197. stringAppend(String&s, const String& a)
  198. {
  199. return s.append(a);
  200. }
  201. inline
  202. String&
  203. stringAppend(String& s, size_t n, char c)
  204. {
  205. return s.append(n, c);
  206. }
  207. template <typename Iterator>
  208. String&
  209. stringAppend(String& s, Iterator begin, Iterator end)
  210. {
  211. return s.append(begin, end);
  212. }
  213. template <typename T>
  214. std::string
  215. toUTF8String(T&& t)
  216. {
  217. return std::forward<T>(t);
  218. }
  219. inline
  220. bool
  221. empty(const std::string& s)
  222. {
  223. return s.empty();
  224. }
  225. } // namespace cxxopts
  226. //ifdef CXXOPTS_USE_UNICODE
  227. #endif
  228. namespace cxxopts
  229. {
  230. namespace
  231. {
  232. #ifdef _WIN32
  233. const std::string LQUOTE("\'");
  234. const std::string RQUOTE("\'");
  235. #else
  236. const std::string LQUOTE("");
  237. const std::string RQUOTE("");
  238. #endif
  239. } // namespace
  240. class Value : public std::enable_shared_from_this<Value>
  241. {
  242. public:
  243. virtual ~Value() = default;
  244. virtual
  245. std::shared_ptr<Value>
  246. clone() const = 0;
  247. virtual void
  248. parse(const std::string& text) const = 0;
  249. virtual void
  250. parse() const = 0;
  251. virtual bool
  252. has_default() const = 0;
  253. virtual bool
  254. is_container() const = 0;
  255. virtual bool
  256. has_implicit() const = 0;
  257. virtual std::string
  258. get_default_value() const = 0;
  259. virtual std::string
  260. get_implicit_value() const = 0;
  261. virtual std::shared_ptr<Value>
  262. default_value(const std::string& value) = 0;
  263. virtual std::shared_ptr<Value>
  264. implicit_value(const std::string& value) = 0;
  265. virtual std::shared_ptr<Value>
  266. no_implicit_value() = 0;
  267. virtual bool
  268. is_boolean() const = 0;
  269. };
  270. class OptionException : public std::exception
  271. {
  272. public:
  273. explicit OptionException(std::string message)
  274. : m_message(std::move(message))
  275. {
  276. }
  277. CXXOPTS_NODISCARD
  278. const char*
  279. what() const noexcept override
  280. {
  281. return m_message.c_str();
  282. }
  283. private:
  284. std::string m_message;
  285. };
  286. class OptionSpecException : public OptionException
  287. {
  288. public:
  289. explicit OptionSpecException(const std::string& message)
  290. : OptionException(message)
  291. {
  292. }
  293. };
  294. class OptionParseException : public OptionException
  295. {
  296. public:
  297. explicit OptionParseException(const std::string& message)
  298. : OptionException(message)
  299. {
  300. }
  301. };
  302. class option_exists_error : public OptionSpecException
  303. {
  304. public:
  305. explicit option_exists_error(const std::string& option)
  306. : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
  307. {
  308. }
  309. };
  310. class invalid_option_format_error : public OptionSpecException
  311. {
  312. public:
  313. explicit invalid_option_format_error(const std::string& format)
  314. : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
  315. {
  316. }
  317. };
  318. class option_syntax_exception : public OptionParseException {
  319. public:
  320. explicit option_syntax_exception(const std::string& text)
  321. : OptionParseException("Argument " + LQUOTE + text + RQUOTE +
  322. " starts with a - but has incorrect syntax")
  323. {
  324. }
  325. };
  326. class option_not_exists_exception : public OptionParseException
  327. {
  328. public:
  329. explicit option_not_exists_exception(const std::string& option)
  330. : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
  331. {
  332. }
  333. };
  334. class missing_argument_exception : public OptionParseException
  335. {
  336. public:
  337. explicit missing_argument_exception(const std::string& option)
  338. : OptionParseException(
  339. "Option " + LQUOTE + option + RQUOTE + " is missing an argument"
  340. )
  341. {
  342. }
  343. };
  344. class option_requires_argument_exception : public OptionParseException
  345. {
  346. public:
  347. explicit option_requires_argument_exception(const std::string& option)
  348. : OptionParseException(
  349. "Option " + LQUOTE + option + RQUOTE + " requires an argument"
  350. )
  351. {
  352. }
  353. };
  354. class option_not_has_argument_exception : public OptionParseException
  355. {
  356. public:
  357. option_not_has_argument_exception
  358. (
  359. const std::string& option,
  360. const std::string& arg
  361. )
  362. : OptionParseException(
  363. "Option " + LQUOTE + option + RQUOTE +
  364. " does not take an argument, but argument " +
  365. LQUOTE + arg + RQUOTE + " given"
  366. )
  367. {
  368. }
  369. };
  370. class option_not_present_exception : public OptionParseException
  371. {
  372. public:
  373. explicit option_not_present_exception(const std::string& option)
  374. : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
  375. {
  376. }
  377. };
  378. class option_has_no_value_exception : public OptionException
  379. {
  380. public:
  381. explicit option_has_no_value_exception(const std::string& option)
  382. : OptionException(
  383. option.empty() ?
  384. ("Option " + LQUOTE + option + RQUOTE + " has no value") :
  385. "Option has no value")
  386. {
  387. }
  388. };
  389. class argument_incorrect_type : public OptionParseException
  390. {
  391. public:
  392. explicit argument_incorrect_type
  393. (
  394. const std::string& arg
  395. )
  396. : OptionParseException(
  397. "Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
  398. )
  399. {
  400. }
  401. };
  402. class option_required_exception : public OptionParseException
  403. {
  404. public:
  405. explicit option_required_exception(const std::string& option)
  406. : OptionParseException(
  407. "Option " + LQUOTE + option + RQUOTE + " is required but not present"
  408. )
  409. {
  410. }
  411. };
  412. template <typename T>
  413. void throw_or_mimic(const std::string& text)
  414. {
  415. static_assert(std::is_base_of<std::exception, T>::value,
  416. "throw_or_mimic only works on std::exception and "
  417. "deriving classes");
  418. #ifndef CXXOPTS_NO_EXCEPTIONS
  419. // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
  420. throw T{text};
  421. #else
  422. // Otherwise manually instantiate the exception, print what() to stderr,
  423. // and exit
  424. T exception{text};
  425. std::cerr << exception.what() << std::endl;
  426. std::exit(EXIT_FAILURE);
  427. #endif
  428. }
  429. namespace values
  430. {
  431. namespace
  432. {
  433. std::basic_regex<char> integer_pattern
  434. ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
  435. std::basic_regex<char> truthy_pattern
  436. ("(t|T)(rue)?|1");
  437. std::basic_regex<char> falsy_pattern
  438. ("(f|F)(alse)?|0");
  439. } // namespace
  440. namespace detail
  441. {
  442. template <typename T, bool B>
  443. struct SignedCheck;
  444. template <typename T>
  445. struct SignedCheck<T, true>
  446. {
  447. template <typename U>
  448. void
  449. operator()(bool negative, U u, const std::string& text)
  450. {
  451. if (negative)
  452. {
  453. if (u > static_cast<U>((std::numeric_limits<T>::min)()))
  454. {
  455. throw_or_mimic<argument_incorrect_type>(text);
  456. }
  457. }
  458. else
  459. {
  460. if (u > static_cast<U>((std::numeric_limits<T>::max)()))
  461. {
  462. throw_or_mimic<argument_incorrect_type>(text);
  463. }
  464. }
  465. }
  466. };
  467. template <typename T>
  468. struct SignedCheck<T, false>
  469. {
  470. template <typename U>
  471. void
  472. operator()(bool, U, const std::string&) {}
  473. };
  474. template <typename T, typename U>
  475. void
  476. check_signed_range(bool negative, U value, const std::string& text)
  477. {
  478. SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
  479. }
  480. } // namespace detail
  481. template <typename R, typename T>
  482. R
  483. checked_negate(T&& t, const std::string&, std::true_type)
  484. {
  485. // if we got to here, then `t` is a positive number that fits into
  486. // `R`. So to avoid MSVC C4146, we first cast it to `R`.
  487. // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
  488. return static_cast<R>(-static_cast<R>(t-1)-1);
  489. }
  490. template <typename R, typename T>
  491. T
  492. checked_negate(T&& t, const std::string& text, std::false_type)
  493. {
  494. throw_or_mimic<argument_incorrect_type>(text);
  495. return t;
  496. }
  497. template <typename T>
  498. void
  499. integer_parser(const std::string& text, T& value)
  500. {
  501. std::smatch match;
  502. std::regex_match(text, match, integer_pattern);
  503. if (match.length() == 0)
  504. {
  505. throw_or_mimic<argument_incorrect_type>(text);
  506. }
  507. if (match.length(4) > 0)
  508. {
  509. value = 0;
  510. return;
  511. }
  512. using US = typename std::make_unsigned<T>::type;
  513. constexpr bool is_signed = std::numeric_limits<T>::is_signed;
  514. const bool negative = match.length(1) > 0;
  515. const uint8_t base = match.length(2) > 0 ? 16 : 10;
  516. auto value_match = match[3];
  517. US result = 0;
  518. for (auto iter = value_match.first; iter != value_match.second; ++iter)
  519. {
  520. US digit = 0;
  521. if (*iter >= '0' && *iter <= '9')
  522. {
  523. digit = static_cast<US>(*iter - '0');
  524. }
  525. else if (base == 16 && *iter >= 'a' && *iter <= 'f')
  526. {
  527. digit = static_cast<US>(*iter - 'a' + 10);
  528. }
  529. else if (base == 16 && *iter >= 'A' && *iter <= 'F')
  530. {
  531. digit = static_cast<US>(*iter - 'A' + 10);
  532. }
  533. else
  534. {
  535. throw_or_mimic<argument_incorrect_type>(text);
  536. }
  537. const US next = static_cast<US>(result * base + digit);
  538. if (result > next)
  539. {
  540. throw_or_mimic<argument_incorrect_type>(text);
  541. }
  542. result = next;
  543. }
  544. detail::check_signed_range<T>(negative, result, text);
  545. if (negative)
  546. {
  547. value = checked_negate<T>(result,
  548. text,
  549. std::integral_constant<bool, is_signed>());
  550. }
  551. else
  552. {
  553. value = static_cast<T>(result);
  554. }
  555. }
  556. template <typename T>
  557. void stringstream_parser(const std::string& text, T& value)
  558. {
  559. std::stringstream in(text);
  560. in >> value;
  561. if (!in) {
  562. throw_or_mimic<argument_incorrect_type>(text);
  563. }
  564. }
  565. inline
  566. void
  567. parse_value(const std::string& text, uint8_t& value)
  568. {
  569. integer_parser(text, value);
  570. }
  571. inline
  572. void
  573. parse_value(const std::string& text, int8_t& value)
  574. {
  575. integer_parser(text, value);
  576. }
  577. inline
  578. void
  579. parse_value(const std::string& text, uint16_t& value)
  580. {
  581. integer_parser(text, value);
  582. }
  583. inline
  584. void
  585. parse_value(const std::string& text, int16_t& value)
  586. {
  587. integer_parser(text, value);
  588. }
  589. inline
  590. void
  591. parse_value(const std::string& text, uint32_t& value)
  592. {
  593. integer_parser(text, value);
  594. }
  595. inline
  596. void
  597. parse_value(const std::string& text, int32_t& value)
  598. {
  599. integer_parser(text, value);
  600. }
  601. inline
  602. void
  603. parse_value(const std::string& text, uint64_t& value)
  604. {
  605. integer_parser(text, value);
  606. }
  607. inline
  608. void
  609. parse_value(const std::string& text, int64_t& value)
  610. {
  611. integer_parser(text, value);
  612. }
  613. inline
  614. void
  615. parse_value(const std::string& text, bool& value)
  616. {
  617. std::smatch result;
  618. std::regex_match(text, result, truthy_pattern);
  619. if (!result.empty())
  620. {
  621. value = true;
  622. return;
  623. }
  624. std::regex_match(text, result, falsy_pattern);
  625. if (!result.empty())
  626. {
  627. value = false;
  628. return;
  629. }
  630. throw_or_mimic<argument_incorrect_type>(text);
  631. }
  632. inline
  633. void
  634. parse_value(const std::string& text, std::string& value)
  635. {
  636. value = text;
  637. }
  638. // The fallback parser. It uses the stringstream parser to parse all types
  639. // that have not been overloaded explicitly. It has to be placed in the
  640. // source code before all other more specialized templates.
  641. template <typename T>
  642. void
  643. parse_value(const std::string& text, T& value) {
  644. stringstream_parser(text, value);
  645. }
  646. template <typename T>
  647. void
  648. parse_value(const std::string& text, std::vector<T>& value)
  649. {
  650. std::stringstream in(text);
  651. std::string token;
  652. while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
  653. T v;
  654. parse_value(token, v);
  655. value.emplace_back(std::move(v));
  656. }
  657. }
  658. #ifdef CXXOPTS_HAS_OPTIONAL
  659. template <typename T>
  660. void
  661. parse_value(const std::string& text, std::optional<T>& value)
  662. {
  663. T result;
  664. parse_value(text, result);
  665. value = std::move(result);
  666. }
  667. #endif
  668. inline
  669. void parse_value(const std::string& text, char& c)
  670. {
  671. if (text.length() != 1)
  672. {
  673. throw_or_mimic<argument_incorrect_type>(text);
  674. }
  675. c = text[0];
  676. }
  677. template <typename T>
  678. struct type_is_container
  679. {
  680. static constexpr bool value = false;
  681. };
  682. template <typename T>
  683. struct type_is_container<std::vector<T>>
  684. {
  685. static constexpr bool value = true;
  686. };
  687. template <typename T>
  688. class abstract_value : public Value
  689. {
  690. using Self = abstract_value<T>;
  691. public:
  692. abstract_value()
  693. : m_result(std::make_shared<T>())
  694. , m_store(m_result.get())
  695. {
  696. }
  697. explicit abstract_value(T* t)
  698. : m_store(t)
  699. {
  700. }
  701. ~abstract_value() override = default;
  702. abstract_value(const abstract_value& rhs)
  703. {
  704. if (rhs.m_result)
  705. {
  706. m_result = std::make_shared<T>();
  707. m_store = m_result.get();
  708. }
  709. else
  710. {
  711. m_store = rhs.m_store;
  712. }
  713. m_default = rhs.m_default;
  714. m_implicit = rhs.m_implicit;
  715. m_default_value = rhs.m_default_value;
  716. m_implicit_value = rhs.m_implicit_value;
  717. }
  718. void
  719. parse(const std::string& text) const override
  720. {
  721. parse_value(text, *m_store);
  722. }
  723. bool
  724. is_container() const override
  725. {
  726. return type_is_container<T>::value;
  727. }
  728. void
  729. parse() const override
  730. {
  731. parse_value(m_default_value, *m_store);
  732. }
  733. bool
  734. has_default() const override
  735. {
  736. return m_default;
  737. }
  738. bool
  739. has_implicit() const override
  740. {
  741. return m_implicit;
  742. }
  743. std::shared_ptr<Value>
  744. default_value(const std::string& value) override
  745. {
  746. m_default = true;
  747. m_default_value = value;
  748. return shared_from_this();
  749. }
  750. std::shared_ptr<Value>
  751. implicit_value(const std::string& value) override
  752. {
  753. m_implicit = true;
  754. m_implicit_value = value;
  755. return shared_from_this();
  756. }
  757. std::shared_ptr<Value>
  758. no_implicit_value() override
  759. {
  760. m_implicit = false;
  761. return shared_from_this();
  762. }
  763. std::string
  764. get_default_value() const override
  765. {
  766. return m_default_value;
  767. }
  768. std::string
  769. get_implicit_value() const override
  770. {
  771. return m_implicit_value;
  772. }
  773. bool
  774. is_boolean() const override
  775. {
  776. return std::is_same<T, bool>::value;
  777. }
  778. const T&
  779. get() const
  780. {
  781. if (m_store == nullptr)
  782. {
  783. return *m_result;
  784. }
  785. return *m_store;
  786. }
  787. protected:
  788. std::shared_ptr<T> m_result;
  789. T* m_store;
  790. bool m_default = false;
  791. bool m_implicit = false;
  792. std::string m_default_value;
  793. std::string m_implicit_value;
  794. };
  795. template <typename T>
  796. class standard_value : public abstract_value<T>
  797. {
  798. public:
  799. using abstract_value<T>::abstract_value;
  800. CXXOPTS_NODISCARD
  801. std::shared_ptr<Value>
  802. clone() const
  803. {
  804. return std::make_shared<standard_value<T>>(*this);
  805. }
  806. };
  807. template <>
  808. class standard_value<bool> : public abstract_value<bool>
  809. {
  810. public:
  811. ~standard_value() override = default;
  812. standard_value()
  813. {
  814. set_default_and_implicit();
  815. }
  816. explicit standard_value(bool* b)
  817. : abstract_value(b)
  818. {
  819. set_default_and_implicit();
  820. }
  821. std::shared_ptr<Value>
  822. clone() const override
  823. {
  824. return std::make_shared<standard_value<bool>>(*this);
  825. }
  826. private:
  827. void
  828. set_default_and_implicit()
  829. {
  830. m_default = true;
  831. m_default_value = "false";
  832. m_implicit = true;
  833. m_implicit_value = "true";
  834. }
  835. };
  836. } // namespace values
  837. template <typename T>
  838. std::shared_ptr<Value>
  839. value()
  840. {
  841. return std::make_shared<values::standard_value<T>>();
  842. }
  843. template <typename T>
  844. std::shared_ptr<Value>
  845. value(T& t)
  846. {
  847. return std::make_shared<values::standard_value<T>>(&t);
  848. }
  849. class OptionAdder;
  850. class OptionDetails
  851. {
  852. public:
  853. OptionDetails
  854. (
  855. std::string short_,
  856. std::string long_,
  857. String desc,
  858. std::shared_ptr<const Value> val
  859. )
  860. : m_short(std::move(short_))
  861. , m_long(std::move(long_))
  862. , m_desc(std::move(desc))
  863. , m_value(std::move(val))
  864. , m_count(0)
  865. {
  866. }
  867. OptionDetails(const OptionDetails& rhs)
  868. : m_desc(rhs.m_desc)
  869. , m_count(rhs.m_count)
  870. {
  871. m_value = rhs.m_value->clone();
  872. }
  873. OptionDetails(OptionDetails&& rhs) = default;
  874. CXXOPTS_NODISCARD
  875. const String&
  876. description() const
  877. {
  878. return m_desc;
  879. }
  880. CXXOPTS_NODISCARD
  881. const Value&
  882. value() const {
  883. return *m_value;
  884. }
  885. CXXOPTS_NODISCARD
  886. std::shared_ptr<Value>
  887. make_storage() const
  888. {
  889. return m_value->clone();
  890. }
  891. CXXOPTS_NODISCARD
  892. const std::string&
  893. short_name() const
  894. {
  895. return m_short;
  896. }
  897. CXXOPTS_NODISCARD
  898. const std::string&
  899. long_name() const
  900. {
  901. return m_long;
  902. }
  903. private:
  904. std::string m_short;
  905. std::string m_long;
  906. String m_desc;
  907. std::shared_ptr<const Value> m_value;
  908. int m_count;
  909. };
  910. struct HelpOptionDetails
  911. {
  912. std::string s;
  913. std::string l;
  914. String desc;
  915. bool has_default;
  916. std::string default_value;
  917. bool has_implicit;
  918. std::string implicit_value;
  919. std::string arg_help;
  920. bool is_container;
  921. bool is_boolean;
  922. };
  923. struct HelpGroupDetails
  924. {
  925. std::string name;
  926. std::string description;
  927. std::vector<HelpOptionDetails> options;
  928. };
  929. class OptionValue
  930. {
  931. public:
  932. void
  933. parse
  934. (
  935. const std::shared_ptr<const OptionDetails>& details,
  936. const std::string& text
  937. )
  938. {
  939. ensure_value(details);
  940. ++m_count;
  941. m_value->parse(text);
  942. m_long_name = &details->long_name();
  943. }
  944. void
  945. parse_default(const std::shared_ptr<const OptionDetails>& details)
  946. {
  947. ensure_value(details);
  948. m_default = true;
  949. m_long_name = &details->long_name();
  950. m_value->parse();
  951. }
  952. CXXOPTS_NODISCARD
  953. size_t
  954. count() const noexcept
  955. {
  956. return m_count;
  957. }
  958. // TODO: maybe default options should count towards the number of arguments
  959. CXXOPTS_NODISCARD
  960. bool
  961. has_default() const noexcept
  962. {
  963. return m_default;
  964. }
  965. template <typename T>
  966. const T&
  967. as() const
  968. {
  969. if (m_value == nullptr) {
  970. throw_or_mimic<option_has_no_value_exception>(
  971. m_long_name == nullptr ? "" : *m_long_name);
  972. }
  973. #ifdef CXXOPTS_NO_RTTI
  974. return static_cast<const values::standard_value<T>&>(*m_value).get();
  975. #else
  976. return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
  977. #endif
  978. }
  979. private:
  980. void
  981. ensure_value(const std::shared_ptr<const OptionDetails>& details)
  982. {
  983. if (m_value == nullptr)
  984. {
  985. m_value = details->make_storage();
  986. }
  987. }
  988. const std::string* m_long_name = nullptr;
  989. // Holding this pointer is safe, since OptionValue's only exist in key-value pairs,
  990. // where the key has the string we point to.
  991. std::shared_ptr<Value> m_value;
  992. size_t m_count = 0;
  993. bool m_default = false;
  994. };
  995. class KeyValue
  996. {
  997. public:
  998. KeyValue(std::string key_, std::string value_)
  999. : m_key(std::move(key_))
  1000. , m_value(std::move(value_))
  1001. {
  1002. }
  1003. CXXOPTS_NODISCARD
  1004. const std::string&
  1005. key() const
  1006. {
  1007. return m_key;
  1008. }
  1009. CXXOPTS_NODISCARD
  1010. const std::string&
  1011. value() const
  1012. {
  1013. return m_value;
  1014. }
  1015. template <typename T>
  1016. T
  1017. as() const
  1018. {
  1019. T result;
  1020. values::parse_value(m_value, result);
  1021. return result;
  1022. }
  1023. private:
  1024. std::string m_key;
  1025. std::string m_value;
  1026. };
  1027. class ParseResult
  1028. {
  1029. public:
  1030. ParseResult(
  1031. std::shared_ptr<
  1032. std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1033. >,
  1034. std::vector<std::string>,
  1035. bool allow_unrecognised,
  1036. int&, char**&);
  1037. size_t
  1038. count(const std::string& o) const
  1039. {
  1040. auto iter = m_options->find(o);
  1041. if (iter == m_options->end())
  1042. {
  1043. return 0;
  1044. }
  1045. auto riter = m_results.find(iter->second);
  1046. return riter->second.count();
  1047. }
  1048. const OptionValue&
  1049. operator[](const std::string& option) const
  1050. {
  1051. auto iter = m_options->find(option);
  1052. if (iter == m_options->end())
  1053. {
  1054. throw_or_mimic<option_not_present_exception>(option);
  1055. }
  1056. auto riter = m_results.find(iter->second);
  1057. return riter->second;
  1058. }
  1059. const std::vector<KeyValue>&
  1060. arguments() const
  1061. {
  1062. return m_sequential;
  1063. }
  1064. private:
  1065. void
  1066. parse(int& argc, char**& argv);
  1067. void
  1068. add_to_option(const std::string& option, const std::string& arg);
  1069. bool
  1070. consume_positional(const std::string& a);
  1071. void
  1072. parse_option
  1073. (
  1074. const std::shared_ptr<OptionDetails>& value,
  1075. const std::string& name,
  1076. const std::string& arg = ""
  1077. );
  1078. void
  1079. parse_default(const std::shared_ptr<OptionDetails>& details);
  1080. void
  1081. checked_parse_arg
  1082. (
  1083. int argc,
  1084. char* argv[],
  1085. int& current,
  1086. const std::shared_ptr<OptionDetails>& value,
  1087. const std::string& name
  1088. );
  1089. const std::shared_ptr<
  1090. std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1091. > m_options;
  1092. std::vector<std::string> m_positional;
  1093. std::vector<std::string>::iterator m_next_positional;
  1094. std::unordered_set<std::string> m_positional_set;
  1095. std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
  1096. bool m_allow_unrecognised;
  1097. std::vector<KeyValue> m_sequential;
  1098. };
  1099. struct Option
  1100. {
  1101. Option
  1102. (
  1103. std::string opts,
  1104. std::string desc,
  1105. std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
  1106. std::string arg_help = ""
  1107. )
  1108. : opts_(std::move(opts))
  1109. , desc_(std::move(desc))
  1110. , value_(std::move(value))
  1111. , arg_help_(std::move(arg_help))
  1112. {
  1113. }
  1114. std::string opts_;
  1115. std::string desc_;
  1116. std::shared_ptr<const Value> value_;
  1117. std::string arg_help_;
  1118. };
  1119. class Options
  1120. {
  1121. using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
  1122. public:
  1123. explicit Options(std::string program, std::string help_string = "")
  1124. : m_program(std::move(program))
  1125. , m_help_string(toLocalString(std::move(help_string)))
  1126. , m_custom_help("[OPTION...]")
  1127. , m_positional_help("positional parameters")
  1128. , m_show_positional(false)
  1129. , m_allow_unrecognised(false)
  1130. , m_options(std::make_shared<OptionMap>())
  1131. , m_next_positional(m_positional.end())
  1132. {
  1133. }
  1134. Options&
  1135. positional_help(std::string help_text)
  1136. {
  1137. m_positional_help = std::move(help_text);
  1138. return *this;
  1139. }
  1140. Options&
  1141. custom_help(std::string help_text)
  1142. {
  1143. m_custom_help = std::move(help_text);
  1144. return *this;
  1145. }
  1146. Options&
  1147. show_positional_help()
  1148. {
  1149. m_show_positional = true;
  1150. return *this;
  1151. }
  1152. Options&
  1153. allow_unrecognised_options()
  1154. {
  1155. m_allow_unrecognised = true;
  1156. return *this;
  1157. }
  1158. ParseResult
  1159. parse(int& argc, char**& argv);
  1160. OptionAdder
  1161. add_options(std::string group = "");
  1162. void
  1163. add_options
  1164. (
  1165. const std::string& group,
  1166. std::initializer_list<Option> options
  1167. );
  1168. void
  1169. add_option
  1170. (
  1171. const std::string& group,
  1172. const Option& option
  1173. );
  1174. void
  1175. add_option
  1176. (
  1177. const std::string& group,
  1178. const std::string& s,
  1179. const std::string& l,
  1180. std::string desc,
  1181. const std::shared_ptr<const Value>& value,
  1182. std::string arg_help
  1183. );
  1184. //parse positional arguments into the given option
  1185. void
  1186. parse_positional(std::string option);
  1187. void
  1188. parse_positional(std::vector<std::string> options);
  1189. void
  1190. parse_positional(std::initializer_list<std::string> options);
  1191. template <typename Iterator>
  1192. void
  1193. parse_positional(Iterator begin, Iterator end) {
  1194. parse_positional(std::vector<std::string>{begin, end});
  1195. }
  1196. std::string
  1197. help(const std::vector<std::string>& groups = {}) const;
  1198. std::vector<std::string>
  1199. groups() const;
  1200. const HelpGroupDetails&
  1201. group_help(const std::string& group) const;
  1202. private:
  1203. void
  1204. add_one_option
  1205. (
  1206. const std::string& option,
  1207. const std::shared_ptr<OptionDetails>& details
  1208. );
  1209. String
  1210. help_one_group(const std::string& group) const;
  1211. void
  1212. generate_group_help
  1213. (
  1214. String& result,
  1215. const std::vector<std::string>& groups
  1216. ) const;
  1217. void
  1218. generate_all_groups_help(String& result) const;
  1219. std::string m_program;
  1220. String m_help_string;
  1221. std::string m_custom_help;
  1222. std::string m_positional_help;
  1223. bool m_show_positional;
  1224. bool m_allow_unrecognised;
  1225. std::shared_ptr<OptionMap> m_options;
  1226. std::vector<std::string> m_positional;
  1227. std::vector<std::string>::iterator m_next_positional;
  1228. std::unordered_set<std::string> m_positional_set;
  1229. //mapping from groups to help options
  1230. std::map<std::string, HelpGroupDetails> m_help;
  1231. };
  1232. class OptionAdder
  1233. {
  1234. public:
  1235. OptionAdder(Options& options, std::string group)
  1236. : m_options(options), m_group(std::move(group))
  1237. {
  1238. }
  1239. OptionAdder&
  1240. operator()
  1241. (
  1242. const std::string& opts,
  1243. const std::string& desc,
  1244. const std::shared_ptr<const Value>& value
  1245. = ::cxxopts::value<bool>(),
  1246. std::string arg_help = ""
  1247. );
  1248. private:
  1249. Options& m_options;
  1250. std::string m_group;
  1251. };
  1252. namespace
  1253. {
  1254. constexpr int OPTION_LONGEST = 30;
  1255. constexpr int OPTION_DESC_GAP = 2;
  1256. std::basic_regex<char> option_matcher
  1257. ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
  1258. std::basic_regex<char> option_specifier
  1259. ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
  1260. String
  1261. format_option
  1262. (
  1263. const HelpOptionDetails& o
  1264. )
  1265. {
  1266. const auto& s = o.s;
  1267. const auto& l = o.l;
  1268. String result = " ";
  1269. if (!s.empty())
  1270. {
  1271. result += "-" + toLocalString(s);
  1272. if (!l.empty())
  1273. {
  1274. result += ",";
  1275. }
  1276. }
  1277. else
  1278. {
  1279. result += " ";
  1280. }
  1281. if (!l.empty())
  1282. {
  1283. result += " --" + toLocalString(l);
  1284. }
  1285. auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg";
  1286. if (!o.is_boolean)
  1287. {
  1288. if (o.has_implicit)
  1289. {
  1290. result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
  1291. }
  1292. else
  1293. {
  1294. result += " " + arg;
  1295. }
  1296. }
  1297. return result;
  1298. }
  1299. String
  1300. format_description
  1301. (
  1302. const HelpOptionDetails& o,
  1303. size_t start,
  1304. size_t width
  1305. )
  1306. {
  1307. auto desc = o.desc;
  1308. if (o.has_default && (!o.is_boolean || o.default_value != "false"))
  1309. {
  1310. if(!o.default_value.empty())
  1311. {
  1312. desc += toLocalString(" (default: " + o.default_value + ")");
  1313. }
  1314. else
  1315. {
  1316. desc += toLocalString(" (default: \"\")");
  1317. }
  1318. }
  1319. String result;
  1320. auto current = std::begin(desc);
  1321. auto startLine = current;
  1322. auto lastSpace = current;
  1323. auto size = size_t{};
  1324. while (current != std::end(desc))
  1325. {
  1326. if (*current == ' ')
  1327. {
  1328. lastSpace = current;
  1329. }
  1330. if (*current == '\n')
  1331. {
  1332. startLine = current + 1;
  1333. lastSpace = startLine;
  1334. }
  1335. else if (size > width)
  1336. {
  1337. if (lastSpace == startLine)
  1338. {
  1339. stringAppend(result, startLine, current + 1);
  1340. stringAppend(result, "\n");
  1341. stringAppend(result, start, ' ');
  1342. startLine = current + 1;
  1343. lastSpace = startLine;
  1344. }
  1345. else
  1346. {
  1347. stringAppend(result, startLine, lastSpace);
  1348. stringAppend(result, "\n");
  1349. stringAppend(result, start, ' ');
  1350. startLine = lastSpace + 1;
  1351. lastSpace = startLine;
  1352. }
  1353. size = 0;
  1354. }
  1355. else
  1356. {
  1357. ++size;
  1358. }
  1359. ++current;
  1360. }
  1361. //append whatever is left
  1362. stringAppend(result, startLine, current);
  1363. return result;
  1364. }
  1365. } // namespace
  1366. inline
  1367. ParseResult::ParseResult
  1368. (
  1369. std::shared_ptr<
  1370. std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1371. > options,
  1372. std::vector<std::string> positional,
  1373. bool allow_unrecognised,
  1374. int& argc, char**& argv
  1375. )
  1376. : m_options(std::move(options))
  1377. , m_positional(std::move(positional))
  1378. , m_next_positional(m_positional.begin())
  1379. , m_allow_unrecognised(allow_unrecognised)
  1380. {
  1381. parse(argc, argv);
  1382. }
  1383. inline
  1384. void
  1385. Options::add_options
  1386. (
  1387. const std::string &group,
  1388. std::initializer_list<Option> options
  1389. )
  1390. {
  1391. OptionAdder option_adder(*this, group);
  1392. for (const auto &option: options)
  1393. {
  1394. option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
  1395. }
  1396. }
  1397. inline
  1398. OptionAdder
  1399. Options::add_options(std::string group)
  1400. {
  1401. return OptionAdder(*this, std::move(group));
  1402. }
  1403. inline
  1404. OptionAdder&
  1405. OptionAdder::operator()
  1406. (
  1407. const std::string& opts,
  1408. const std::string& desc,
  1409. const std::shared_ptr<const Value>& value,
  1410. std::string arg_help
  1411. )
  1412. {
  1413. std::match_results<const char*> result;
  1414. std::regex_match(opts.c_str(), result, option_specifier);
  1415. if (result.empty())
  1416. {
  1417. throw_or_mimic<invalid_option_format_error>(opts);
  1418. }
  1419. const auto& short_match = result[2];
  1420. const auto& long_match = result[3];
  1421. if (!short_match.length() && !long_match.length())
  1422. {
  1423. throw_or_mimic<invalid_option_format_error>(opts);
  1424. } else if (long_match.length() == 1 && short_match.length())
  1425. {
  1426. throw_or_mimic<invalid_option_format_error>(opts);
  1427. }
  1428. auto option_names = []
  1429. (
  1430. const std::sub_match<const char*>& short_,
  1431. const std::sub_match<const char*>& long_
  1432. )
  1433. {
  1434. if (long_.length() == 1)
  1435. {
  1436. return std::make_tuple(long_.str(), short_.str());
  1437. }
  1438. return std::make_tuple(short_.str(), long_.str());
  1439. }(short_match, long_match);
  1440. m_options.add_option
  1441. (
  1442. m_group,
  1443. std::get<0>(option_names),
  1444. std::get<1>(option_names),
  1445. desc,
  1446. value,
  1447. std::move(arg_help)
  1448. );
  1449. return *this;
  1450. }
  1451. inline
  1452. void
  1453. ParseResult::parse_default(const std::shared_ptr<OptionDetails>& details)
  1454. {
  1455. m_results[details].parse_default(details);
  1456. }
  1457. inline
  1458. void
  1459. ParseResult::parse_option
  1460. (
  1461. const std::shared_ptr<OptionDetails>& value,
  1462. const std::string& /*name*/,
  1463. const std::string& arg
  1464. )
  1465. {
  1466. auto& result = m_results[value];
  1467. result.parse(value, arg);
  1468. m_sequential.emplace_back(value->long_name(), arg);
  1469. }
  1470. inline
  1471. void
  1472. ParseResult::checked_parse_arg
  1473. (
  1474. int argc,
  1475. char* argv[],
  1476. int& current,
  1477. const std::shared_ptr<OptionDetails>& value,
  1478. const std::string& name
  1479. )
  1480. {
  1481. if (current + 1 >= argc)
  1482. {
  1483. if (value->value().has_implicit())
  1484. {
  1485. parse_option(value, name, value->value().get_implicit_value());
  1486. }
  1487. else
  1488. {
  1489. throw_or_mimic<missing_argument_exception>(name);
  1490. }
  1491. }
  1492. else
  1493. {
  1494. if (value->value().has_implicit())
  1495. {
  1496. parse_option(value, name, value->value().get_implicit_value());
  1497. }
  1498. else
  1499. {
  1500. parse_option(value, name, argv[current + 1]);
  1501. ++current;
  1502. }
  1503. }
  1504. }
  1505. inline
  1506. void
  1507. ParseResult::add_to_option(const std::string& option, const std::string& arg)
  1508. {
  1509. auto iter = m_options->find(option);
  1510. if (iter == m_options->end())
  1511. {
  1512. throw_or_mimic<option_not_exists_exception>(option);
  1513. }
  1514. parse_option(iter->second, option, arg);
  1515. }
  1516. inline
  1517. bool
  1518. ParseResult::consume_positional(const std::string& a)
  1519. {
  1520. while (m_next_positional != m_positional.end())
  1521. {
  1522. auto iter = m_options->find(*m_next_positional);
  1523. if (iter != m_options->end())
  1524. {
  1525. auto& result = m_results[iter->second];
  1526. if (!iter->second->value().is_container())
  1527. {
  1528. if (result.count() == 0)
  1529. {
  1530. add_to_option(*m_next_positional, a);
  1531. ++m_next_positional;
  1532. return true;
  1533. }
  1534. ++m_next_positional;
  1535. continue;
  1536. }
  1537. add_to_option(*m_next_positional, a);
  1538. return true;
  1539. }
  1540. throw_or_mimic<option_not_exists_exception>(*m_next_positional);
  1541. }
  1542. return false;
  1543. }
  1544. inline
  1545. void
  1546. Options::parse_positional(std::string option)
  1547. {
  1548. parse_positional(std::vector<std::string>{std::move(option)});
  1549. }
  1550. inline
  1551. void
  1552. Options::parse_positional(std::vector<std::string> options)
  1553. {
  1554. m_positional = std::move(options);
  1555. m_next_positional = m_positional.begin();
  1556. m_positional_set.insert(m_positional.begin(), m_positional.end());
  1557. }
  1558. inline
  1559. void
  1560. Options::parse_positional(std::initializer_list<std::string> options)
  1561. {
  1562. parse_positional(std::vector<std::string>(options));
  1563. }
  1564. inline
  1565. ParseResult
  1566. Options::parse(int& argc, char**& argv)
  1567. {
  1568. ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
  1569. return result;
  1570. }
  1571. inline
  1572. void
  1573. ParseResult::parse(int& argc, char**& argv)
  1574. {
  1575. int current = 1;
  1576. int nextKeep = 1;
  1577. bool consume_remaining = false;
  1578. while (current != argc)
  1579. {
  1580. if (strcmp(argv[current], "--") == 0)
  1581. {
  1582. consume_remaining = true;
  1583. ++current;
  1584. break;
  1585. }
  1586. std::match_results<const char*> result;
  1587. std::regex_match(argv[current], result, option_matcher);
  1588. if (result.empty())
  1589. {
  1590. //not a flag
  1591. // but if it starts with a `-`, then it's an error
  1592. if (argv[current][0] == '-' && argv[current][1] != '\0') {
  1593. if (!m_allow_unrecognised) {
  1594. throw_or_mimic<option_syntax_exception>(argv[current]);
  1595. }
  1596. }
  1597. //if true is returned here then it was consumed, otherwise it is
  1598. //ignored
  1599. if (consume_positional(argv[current]))
  1600. {
  1601. }
  1602. else
  1603. {
  1604. argv[nextKeep] = argv[current];
  1605. ++nextKeep;
  1606. }
  1607. //if we return from here then it was parsed successfully, so continue
  1608. }
  1609. else
  1610. {
  1611. //short or long option?
  1612. if (result[4].length() != 0)
  1613. {
  1614. const std::string& s = result[4];
  1615. for (std::size_t i = 0; i != s.size(); ++i)
  1616. {
  1617. std::string name(1, s[i]);
  1618. auto iter = m_options->find(name);
  1619. if (iter == m_options->end())
  1620. {
  1621. if (m_allow_unrecognised)
  1622. {
  1623. continue;
  1624. }
  1625. //error
  1626. throw_or_mimic<option_not_exists_exception>(name);
  1627. }
  1628. auto value = iter->second;
  1629. if (i + 1 == s.size())
  1630. {
  1631. //it must be the last argument
  1632. checked_parse_arg(argc, argv, current, value, name);
  1633. }
  1634. else if (value->value().has_implicit())
  1635. {
  1636. parse_option(value, name, value->value().get_implicit_value());
  1637. }
  1638. else
  1639. {
  1640. //error
  1641. throw_or_mimic<option_requires_argument_exception>(name);
  1642. }
  1643. }
  1644. }
  1645. else if (result[1].length() != 0)
  1646. {
  1647. const std::string& name = result[1];
  1648. auto iter = m_options->find(name);
  1649. if (iter == m_options->end())
  1650. {
  1651. if (m_allow_unrecognised)
  1652. {
  1653. // keep unrecognised options in argument list, skip to next argument
  1654. argv[nextKeep] = argv[current];
  1655. ++nextKeep;
  1656. ++current;
  1657. continue;
  1658. }
  1659. //error
  1660. throw_or_mimic<option_not_exists_exception>(name);
  1661. }
  1662. auto opt = iter->second;
  1663. //equals provided for long option?
  1664. if (result[2].length() != 0)
  1665. {
  1666. //parse the option given
  1667. parse_option(opt, name, result[3]);
  1668. }
  1669. else
  1670. {
  1671. //parse the next argument
  1672. checked_parse_arg(argc, argv, current, opt, name);
  1673. }
  1674. }
  1675. }
  1676. ++current;
  1677. }
  1678. for (auto& opt : *m_options)
  1679. {
  1680. auto& detail = opt.second;
  1681. const auto& value = detail->value();
  1682. auto& store = m_results[detail];
  1683. if(value.has_default() && !store.count() && !store.has_default()){
  1684. parse_default(detail);
  1685. }
  1686. }
  1687. if (consume_remaining)
  1688. {
  1689. while (current < argc)
  1690. {
  1691. if (!consume_positional(argv[current])) {
  1692. break;
  1693. }
  1694. ++current;
  1695. }
  1696. //adjust argv for any that couldn't be swallowed
  1697. while (current != argc) {
  1698. argv[nextKeep] = argv[current];
  1699. ++nextKeep;
  1700. ++current;
  1701. }
  1702. }
  1703. argc = nextKeep;
  1704. }
  1705. inline
  1706. void
  1707. Options::add_option
  1708. (
  1709. const std::string& group,
  1710. const Option& option
  1711. )
  1712. {
  1713. add_options(group, {option});
  1714. }
  1715. inline
  1716. void
  1717. Options::add_option
  1718. (
  1719. const std::string& group,
  1720. const std::string& s,
  1721. const std::string& l,
  1722. std::string desc,
  1723. const std::shared_ptr<const Value>& value,
  1724. std::string arg_help
  1725. )
  1726. {
  1727. auto stringDesc = toLocalString(std::move(desc));
  1728. auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
  1729. if (!s.empty())
  1730. {
  1731. add_one_option(s, option);
  1732. }
  1733. if (!l.empty())
  1734. {
  1735. add_one_option(l, option);
  1736. }
  1737. //add the help details
  1738. auto& options = m_help[group];
  1739. options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
  1740. value->has_default(), value->get_default_value(),
  1741. value->has_implicit(), value->get_implicit_value(),
  1742. std::move(arg_help),
  1743. value->is_container(),
  1744. value->is_boolean()});
  1745. }
  1746. inline
  1747. void
  1748. Options::add_one_option
  1749. (
  1750. const std::string& option,
  1751. const std::shared_ptr<OptionDetails>& details
  1752. )
  1753. {
  1754. auto in = m_options->emplace(option, details);
  1755. if (!in.second)
  1756. {
  1757. throw_or_mimic<option_exists_error>(option);
  1758. }
  1759. }
  1760. inline
  1761. String
  1762. Options::help_one_group(const std::string& g) const
  1763. {
  1764. using OptionHelp = std::vector<std::pair<String, String>>;
  1765. auto group = m_help.find(g);
  1766. if (group == m_help.end())
  1767. {
  1768. return "";
  1769. }
  1770. OptionHelp format;
  1771. size_t longest = 0;
  1772. String result;
  1773. if (!g.empty())
  1774. {
  1775. result += toLocalString(" " + g + " options:\n");
  1776. }
  1777. for (const auto& o : group->second.options)
  1778. {
  1779. if (m_positional_set.find(o.l) != m_positional_set.end() &&
  1780. !m_show_positional)
  1781. {
  1782. continue;
  1783. }
  1784. auto s = format_option(o);
  1785. longest = (std::max)(longest, stringLength(s));
  1786. format.push_back(std::make_pair(s, String()));
  1787. }
  1788. longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
  1789. //widest allowed description
  1790. auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
  1791. auto fiter = format.begin();
  1792. for (const auto& o : group->second.options)
  1793. {
  1794. if (m_positional_set.find(o.l) != m_positional_set.end() &&
  1795. !m_show_positional)
  1796. {
  1797. continue;
  1798. }
  1799. auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
  1800. result += fiter->first;
  1801. if (stringLength(fiter->first) > longest)
  1802. {
  1803. result += '\n';
  1804. result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
  1805. }
  1806. else
  1807. {
  1808. result += toLocalString(std::string(longest + OPTION_DESC_GAP -
  1809. stringLength(fiter->first),
  1810. ' '));
  1811. }
  1812. result += d;
  1813. result += '\n';
  1814. ++fiter;
  1815. }
  1816. return result;
  1817. }
  1818. inline
  1819. void
  1820. Options::generate_group_help
  1821. (
  1822. String& result,
  1823. const std::vector<std::string>& print_groups
  1824. ) const
  1825. {
  1826. for (size_t i = 0; i != print_groups.size(); ++i)
  1827. {
  1828. const String& group_help_text = help_one_group(print_groups[i]);
  1829. if (empty(group_help_text))
  1830. {
  1831. continue;
  1832. }
  1833. result += group_help_text;
  1834. if (i < print_groups.size() - 1)
  1835. {
  1836. result += '\n';
  1837. }
  1838. }
  1839. }
  1840. inline
  1841. void
  1842. Options::generate_all_groups_help(String& result) const
  1843. {
  1844. std::vector<std::string> all_groups;
  1845. all_groups.reserve(m_help.size());
  1846. for (const auto& group : m_help)
  1847. {
  1848. all_groups.push_back(group.first);
  1849. }
  1850. generate_group_help(result, all_groups);
  1851. }
  1852. inline
  1853. std::string
  1854. Options::help(const std::vector<std::string>& help_groups) const
  1855. {
  1856. String result = m_help_string + "\nUsage:\n " +
  1857. toLocalString(m_program) + " " + toLocalString(m_custom_help);
  1858. if (!m_positional.empty() && !m_positional_help.empty()) {
  1859. result += " " + toLocalString(m_positional_help);
  1860. }
  1861. result += "\n\n";
  1862. if (help_groups.empty())
  1863. {
  1864. generate_all_groups_help(result);
  1865. }
  1866. else
  1867. {
  1868. generate_group_help(result, help_groups);
  1869. }
  1870. return toUTF8String(result);
  1871. }
  1872. inline
  1873. std::vector<std::string>
  1874. Options::groups() const
  1875. {
  1876. std::vector<std::string> g;
  1877. std::transform(
  1878. m_help.begin(),
  1879. m_help.end(),
  1880. std::back_inserter(g),
  1881. [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
  1882. {
  1883. return pair.first;
  1884. }
  1885. );
  1886. return g;
  1887. }
  1888. inline
  1889. const HelpGroupDetails&
  1890. Options::group_help(const std::string& group) const
  1891. {
  1892. return m_help.at(group);
  1893. }
  1894. } // namespace cxxopts
  1895. #endif //CXXOPTS_HPP_INCLUDED