🛠️🐜 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.

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