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.

1311 lines
25 KiB

  1. /*
  2. Copyright (c) 2014 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 CXX_OPTS_HPP
  20. #define CXX_OPTS_HPP
  21. #if defined(__GNUC__)
  22. #pragma GCC diagnostic push
  23. #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
  24. #endif
  25. #include <exception>
  26. #include <iostream>
  27. #include <map>
  28. #include <memory>
  29. #include <regex>
  30. #include <sstream>
  31. #include <string>
  32. #include <vector>
  33. //when we ask cxxopts to use Unicode, help strings are processed using ICU,
  34. //which results in the correct lengths being computed for strings when they
  35. //are formatted for the help output
  36. //it is necessary to make sure that <unicode/unistr.h> can be found by the
  37. //compiler, and that icu-uc is linked in to the binary.
  38. #ifdef CXXOPTS_USE_UNICODE
  39. #include <unicode/unistr.h>
  40. namespace cxxopts
  41. {
  42. typedef icu::UnicodeString String;
  43. inline
  44. String
  45. toLocalString(std::string s)
  46. {
  47. return icu::UnicodeString::fromUTF8(s);
  48. }
  49. class UnicodeStringIterator : public
  50. std::iterator<std::forward_iterator_tag, int32_t>
  51. {
  52. public:
  53. UnicodeStringIterator(const icu::UnicodeString* s, int32_t pos)
  54. : s(s)
  55. , i(pos)
  56. {
  57. }
  58. value_type
  59. operator*() const
  60. {
  61. return s->char32At(i);
  62. }
  63. bool
  64. operator==(const UnicodeStringIterator& rhs) const
  65. {
  66. return s == rhs.s && i == rhs.i;
  67. }
  68. bool
  69. operator!=(const UnicodeStringIterator& rhs) const
  70. {
  71. return !(*this == rhs);
  72. }
  73. UnicodeStringIterator&
  74. operator++()
  75. {
  76. ++i;
  77. return *this;
  78. }
  79. UnicodeStringIterator
  80. operator+(int32_t v)
  81. {
  82. return UnicodeStringIterator(s, i + v);
  83. }
  84. private:
  85. const icu::UnicodeString* s;
  86. int32_t i;
  87. };
  88. inline
  89. String&
  90. stringAppend(String&s, String a)
  91. {
  92. return s.append(std::move(a));
  93. }
  94. inline
  95. String&
  96. stringAppend(String& s, int n, UChar32 c)
  97. {
  98. for (int i = 0; i != n; ++i)
  99. {
  100. s.append(c);
  101. }
  102. return s;
  103. }
  104. template <typename Iterator>
  105. String&
  106. stringAppend(String& s, Iterator begin, Iterator end)
  107. {
  108. while (begin != end)
  109. {
  110. s.append(*begin);
  111. ++begin;
  112. }
  113. return s;
  114. }
  115. inline
  116. size_t
  117. stringLength(const String& s)
  118. {
  119. return s.length();
  120. }
  121. inline
  122. std::string
  123. toUTF8String(const String& s)
  124. {
  125. std::string result;
  126. s.toUTF8String(result);
  127. return result;
  128. }
  129. }
  130. namespace std
  131. {
  132. cxxopts::UnicodeStringIterator
  133. begin(const icu::UnicodeString& s)
  134. {
  135. return cxxopts::UnicodeStringIterator(&s, 0);
  136. }
  137. cxxopts::UnicodeStringIterator
  138. end(const icu::UnicodeString& s)
  139. {
  140. return cxxopts::UnicodeStringIterator(&s, s.length());
  141. }
  142. }
  143. //ifdef CXXOPTS_USE_UNICODE
  144. #else
  145. namespace cxxopts
  146. {
  147. typedef std::string String;
  148. template <typename T>
  149. T
  150. toLocalString(T&& t)
  151. {
  152. return t;
  153. }
  154. inline
  155. size_t
  156. stringLength(const String& s)
  157. {
  158. return s.length();
  159. }
  160. inline
  161. String&
  162. stringAppend(String&s, String a)
  163. {
  164. return s.append(std::move(a));
  165. }
  166. inline
  167. String&
  168. stringAppend(String& s, size_t n, char c)
  169. {
  170. return s.append(n, c);
  171. }
  172. template <typename Iterator>
  173. String&
  174. stringAppend(String& s, Iterator begin, Iterator end)
  175. {
  176. return s.append(begin, end);
  177. }
  178. template <typename T>
  179. std::string
  180. toUTF8String(T&& t)
  181. {
  182. return std::forward<T>(t);
  183. }
  184. }
  185. //ifdef CXXOPTS_USE_UNICODE
  186. #endif
  187. namespace cxxopts
  188. {
  189. class Value : public std::enable_shared_from_this<Value>
  190. {
  191. public:
  192. virtual void
  193. parse(const std::string& text) const = 0;
  194. virtual void
  195. parse() const = 0;
  196. virtual bool
  197. has_arg() const = 0;
  198. virtual bool
  199. has_default() const = 0;
  200. virtual bool
  201. has_implicit() const = 0;
  202. virtual std::string
  203. get_default_value() const = 0;
  204. virtual std::string
  205. get_implicit_value() const = 0;
  206. virtual std::shared_ptr<Value>
  207. default_value(const std::string& value) = 0;
  208. virtual std::shared_ptr<Value>
  209. implicit_value(const std::string& value) = 0;
  210. };
  211. class OptionException : public std::exception
  212. {
  213. public:
  214. OptionException(const std::string& message)
  215. : m_message(message)
  216. {
  217. }
  218. virtual const char*
  219. what() const noexcept
  220. {
  221. return m_message.c_str();
  222. }
  223. private:
  224. std::string m_message;
  225. };
  226. class OptionSpecException : public OptionException
  227. {
  228. public:
  229. OptionSpecException(const std::string& message)
  230. : OptionException(message)
  231. {
  232. }
  233. };
  234. class OptionParseException : public OptionException
  235. {
  236. public:
  237. OptionParseException(const std::string& message)
  238. : OptionException(message)
  239. {
  240. }
  241. };
  242. class option_exists_error : public OptionSpecException
  243. {
  244. public:
  245. option_exists_error(const std::string& option)
  246. : OptionSpecException(u8"Option ‘" + option + u8"’ already exists")
  247. {
  248. }
  249. };
  250. class invalid_option_format_error : public OptionSpecException
  251. {
  252. public:
  253. invalid_option_format_error(const std::string& format)
  254. : OptionSpecException(u8"Invalid option format ‘" + format + u8"")
  255. {
  256. }
  257. };
  258. class option_not_exists_exception : public OptionParseException
  259. {
  260. public:
  261. option_not_exists_exception(const std::string& option)
  262. : OptionParseException(u8"Option ‘" + option + u8"’ does not exist")
  263. {
  264. }
  265. };
  266. class missing_argument_exception : public OptionParseException
  267. {
  268. public:
  269. missing_argument_exception(const std::string& option)
  270. : OptionParseException(u8"Option ‘" + option + u8"’ is missing an argument")
  271. {
  272. }
  273. };
  274. class option_requires_argument_exception : public OptionParseException
  275. {
  276. public:
  277. option_requires_argument_exception(const std::string& option)
  278. : OptionParseException(u8"Option ‘" + option + u8"’ requires an argument")
  279. {
  280. }
  281. };
  282. class option_not_has_argument_exception : public OptionParseException
  283. {
  284. public:
  285. option_not_has_argument_exception
  286. (
  287. const std::string& option,
  288. const std::string& arg
  289. )
  290. : OptionParseException(
  291. u8"Option ‘" + option + u8"’ does not take an argument, but argument‘"
  292. + arg + "’ given")
  293. {
  294. }
  295. };
  296. class option_not_present_exception : public OptionParseException
  297. {
  298. public:
  299. option_not_present_exception(const std::string& option)
  300. : OptionParseException(u8"Option ‘" + option + u8"’ not present")
  301. {
  302. }
  303. };
  304. class argument_incorrect_type : public OptionParseException
  305. {
  306. public:
  307. argument_incorrect_type
  308. (
  309. const std::string& arg
  310. )
  311. : OptionParseException(
  312. u8"Argument ‘" + arg + u8"’ failed to parse"
  313. )
  314. {
  315. }
  316. };
  317. namespace values
  318. {
  319. template <typename T>
  320. void
  321. parse_value(const std::string& text, T& value)
  322. {
  323. std::istringstream is(text);
  324. if (!(is >> value))
  325. {
  326. std::cerr << "cannot parse empty value" << std::endl;
  327. throw argument_incorrect_type(text);
  328. }
  329. if (is.rdbuf()->in_avail() != 0)
  330. {
  331. throw argument_incorrect_type(text);
  332. }
  333. }
  334. template <typename T>
  335. void
  336. parse_value(const std::string& text, std::vector<T>& value)
  337. {
  338. T v;
  339. parse_value(text, v);
  340. value.push_back(v);
  341. }
  342. inline
  343. void
  344. parse_value(const std::string& /*text*/, bool& value)
  345. {
  346. //TODO recognise on, off, yes, no, enable, disable
  347. //so that we can write --long=yes explicitly
  348. value = true;
  349. }
  350. inline
  351. void
  352. parse_value(const std::string& text, std::string& value)
  353. {
  354. value = text;
  355. }
  356. template <typename T>
  357. struct value_has_arg
  358. {
  359. static constexpr bool value = true;
  360. };
  361. template <>
  362. struct value_has_arg<bool>
  363. {
  364. static constexpr bool value = false;
  365. };
  366. template <typename T>
  367. class standard_value : public Value
  368. {
  369. public:
  370. standard_value()
  371. : m_result(std::make_shared<T>())
  372. , m_store(m_result.get())
  373. {
  374. }
  375. standard_value(T* t)
  376. : m_store(t)
  377. {
  378. }
  379. void
  380. parse(const std::string& text) const
  381. {
  382. if (m_implicit && text.empty())
  383. {
  384. parse_value(m_implicit_value, *m_store);
  385. }
  386. else
  387. {
  388. parse_value(text, *m_store);
  389. }
  390. }
  391. void
  392. parse() const
  393. {
  394. parse_value(m_default_value, *m_store);
  395. }
  396. bool
  397. has_arg() const
  398. {
  399. return value_has_arg<T>::value;
  400. }
  401. bool
  402. has_default() const
  403. {
  404. return m_default;
  405. }
  406. bool
  407. has_implicit() const
  408. {
  409. return m_implicit;
  410. }
  411. virtual std::shared_ptr<Value>
  412. default_value(const std::string& value){
  413. m_default = true;
  414. m_default_value = value;
  415. return shared_from_this();
  416. }
  417. virtual std::shared_ptr<Value>
  418. implicit_value(const std::string& value){
  419. m_implicit = true;
  420. m_implicit_value = value;
  421. return shared_from_this();
  422. }
  423. std::string
  424. get_default_value() const
  425. {
  426. return m_default_value;
  427. }
  428. std::string
  429. get_implicit_value() const
  430. {
  431. return m_implicit_value;
  432. }
  433. const T&
  434. get() const
  435. {
  436. if (m_store == nullptr)
  437. {
  438. return *m_result;
  439. }
  440. else
  441. {
  442. return *m_store;
  443. }
  444. }
  445. protected:
  446. std::shared_ptr<T> m_result;
  447. T* m_store;
  448. bool m_default = false;
  449. std::string m_default_value;
  450. bool m_implicit = false;
  451. std::string m_implicit_value;
  452. };
  453. }
  454. template <typename T>
  455. std::shared_ptr<Value>
  456. value()
  457. {
  458. return std::make_shared<values::standard_value<T>>();
  459. }
  460. template <typename T>
  461. std::shared_ptr<Value>
  462. value(T& t)
  463. {
  464. return std::make_shared<values::standard_value<T>>(&t);
  465. }
  466. class OptionAdder;
  467. class OptionDetails
  468. {
  469. public:
  470. OptionDetails
  471. (
  472. const String& description,
  473. std::shared_ptr<const Value> value
  474. )
  475. : m_desc(description)
  476. , m_value(value)
  477. , m_count(0)
  478. {
  479. }
  480. const String&
  481. description() const
  482. {
  483. return m_desc;
  484. }
  485. bool
  486. has_arg() const
  487. {
  488. return m_value->has_arg();
  489. }
  490. void
  491. parse(const std::string& text)
  492. {
  493. m_value->parse(text);
  494. ++m_count;
  495. }
  496. void
  497. parse_default()
  498. {
  499. m_value->parse();
  500. ++m_count;
  501. }
  502. int
  503. count() const
  504. {
  505. return m_count;
  506. }
  507. const Value& value() const {
  508. return *m_value;
  509. }
  510. template <typename T>
  511. const T&
  512. as() const
  513. {
  514. #ifdef CXXOPTS_NO_RTTI
  515. return static_cast<const values::standard_value<T>&>(*m_value).get();
  516. #else
  517. return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
  518. #endif
  519. }
  520. private:
  521. String m_desc;
  522. std::shared_ptr<const Value> m_value;
  523. int m_count;
  524. };
  525. struct HelpOptionDetails
  526. {
  527. std::string s;
  528. std::string l;
  529. String desc;
  530. bool has_arg;
  531. bool has_default;
  532. std::string default_value;
  533. bool has_implicit;
  534. std::string implicit_value;
  535. std::string arg_help;
  536. };
  537. struct HelpGroupDetails
  538. {
  539. std::string name;
  540. std::string description;
  541. std::vector<HelpOptionDetails> options;
  542. };
  543. class Options
  544. {
  545. public:
  546. Options(std::string program, std::string help_string = "")
  547. : m_program(std::move(program))
  548. , m_help_string(toLocalString(std::move(help_string)))
  549. {
  550. }
  551. inline
  552. void
  553. parse(int& argc, char**& argv);
  554. inline
  555. OptionAdder
  556. add_options(std::string group = "");
  557. inline
  558. void
  559. add_option
  560. (
  561. const std::string& group,
  562. const std::string& s,
  563. const std::string& l,
  564. std::string desc,
  565. std::shared_ptr<const Value> value,
  566. std::string arg_help
  567. );
  568. int
  569. count(const std::string& o) const
  570. {
  571. auto iter = m_options.find(o);
  572. if (iter == m_options.end())
  573. {
  574. return 0;
  575. }
  576. return iter->second->count();
  577. }
  578. const OptionDetails&
  579. operator[](const std::string& option) const
  580. {
  581. auto iter = m_options.find(option);
  582. if (iter == m_options.end())
  583. {
  584. throw option_not_present_exception(option);
  585. }
  586. return *iter->second;
  587. }
  588. //parse positional arguments into the given option
  589. inline
  590. void
  591. parse_positional(std::string option);
  592. inline
  593. std::string
  594. help(const std::vector<std::string>& groups = {""}) const;
  595. inline
  596. const std::vector<std::string>
  597. groups() const;
  598. inline
  599. const HelpGroupDetails&
  600. group_help(const std::string& group) const;
  601. private:
  602. inline
  603. void
  604. add_one_option
  605. (
  606. const std::string& option,
  607. std::shared_ptr<OptionDetails> details
  608. );
  609. inline
  610. bool
  611. consume_positional(std::string a);
  612. inline
  613. void
  614. add_to_option(const std::string& option, const std::string& arg);
  615. inline
  616. void
  617. parse_option
  618. (
  619. std::shared_ptr<OptionDetails> value,
  620. const std::string& name,
  621. const std::string& arg = ""
  622. );
  623. inline
  624. void
  625. checked_parse_arg
  626. (
  627. int argc,
  628. char* argv[],
  629. int& current,
  630. std::shared_ptr<OptionDetails> value,
  631. const std::string& name
  632. );
  633. inline
  634. String
  635. help_one_group(const std::string& group) const;
  636. std::string m_program;
  637. String m_help_string;
  638. std::map<std::string, std::shared_ptr<OptionDetails>> m_options;
  639. std::string m_positional;
  640. //mapping from groups to help options
  641. std::map<std::string, HelpGroupDetails> m_help;
  642. };
  643. class OptionAdder
  644. {
  645. public:
  646. OptionAdder(Options& options, std::string group)
  647. : m_options(options), m_group(std::move(group))
  648. {
  649. }
  650. inline
  651. OptionAdder&
  652. operator()
  653. (
  654. const std::string& opts,
  655. const std::string& desc,
  656. std::shared_ptr<const Value> value
  657. = ::cxxopts::value<bool>(),
  658. std::string arg_help = ""
  659. );
  660. private:
  661. Options& m_options;
  662. std::string m_group;
  663. };
  664. }
  665. namespace cxxopts
  666. {
  667. namespace
  668. {
  669. constexpr int OPTION_LONGEST = 30;
  670. constexpr int OPTION_DESC_GAP = 2;
  671. std::basic_regex<char> option_matcher
  672. ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([a-zA-Z]+)");
  673. std::basic_regex<char> option_specifier
  674. ("(([a-zA-Z]),)?([a-zA-Z0-9][-_a-zA-Z0-9]+)");
  675. String
  676. format_option
  677. (
  678. const HelpOptionDetails& o
  679. )
  680. {
  681. auto& s = o.s;
  682. auto& l = o.l;
  683. String result = " ";
  684. if (s.size() > 0)
  685. {
  686. result += "-" + toLocalString(s) + ",";
  687. }
  688. else
  689. {
  690. result += " ";
  691. }
  692. if (l.size() > 0)
  693. {
  694. result += " --" + toLocalString(l);
  695. }
  696. if (o.has_arg)
  697. {
  698. auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
  699. if (o.has_implicit)
  700. {
  701. result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
  702. }
  703. else
  704. {
  705. result += " " + arg;
  706. }
  707. }
  708. return result;
  709. }
  710. String
  711. format_description
  712. (
  713. const HelpOptionDetails& o,
  714. size_t start,
  715. size_t width
  716. )
  717. {
  718. auto desc = o.desc;
  719. if (o.has_default)
  720. {
  721. desc += toLocalString(" (default:" + o.default_value + ")");
  722. }
  723. String result;
  724. auto current = std::begin(desc);
  725. auto startLine = current;
  726. auto lastSpace = current;
  727. auto size = size_t{};
  728. while (current != std::end(desc))
  729. {
  730. if (*current == ' ')
  731. {
  732. lastSpace = current;
  733. }
  734. if (size > width)
  735. {
  736. if (lastSpace == startLine)
  737. {
  738. stringAppend(result, startLine, current + 1);
  739. stringAppend(result, "\n");
  740. stringAppend(result, start, ' ');
  741. startLine = current + 1;
  742. lastSpace = startLine;
  743. }
  744. else
  745. {
  746. stringAppend(result, startLine, lastSpace);
  747. stringAppend(result, "\n");
  748. stringAppend(result, start, ' ');
  749. startLine = lastSpace + 1;
  750. }
  751. size = 0;
  752. }
  753. else
  754. {
  755. ++size;
  756. }
  757. ++current;
  758. }
  759. //append whatever is left
  760. stringAppend(result, startLine, current);
  761. return result;
  762. }
  763. }
  764. OptionAdder
  765. Options::add_options(std::string group)
  766. {
  767. return OptionAdder(*this, std::move(group));
  768. }
  769. OptionAdder&
  770. OptionAdder::operator()
  771. (
  772. const std::string& opts,
  773. const std::string& desc,
  774. std::shared_ptr<const Value> value,
  775. std::string arg_help
  776. )
  777. {
  778. std::match_results<const char*> result;
  779. std::regex_match(opts.c_str(), result, option_specifier);
  780. if (result.empty())
  781. {
  782. throw invalid_option_format_error(opts);
  783. }
  784. const auto& s = result[2];
  785. const auto& l = result[3];
  786. m_options.add_option(m_group, s.str(), l.str(), desc, value,
  787. std::move(arg_help));
  788. return *this;
  789. }
  790. void
  791. Options::parse_option
  792. (
  793. std::shared_ptr<OptionDetails> value,
  794. const std::string& /*name*/,
  795. const std::string& arg
  796. )
  797. {
  798. value->parse(arg);
  799. }
  800. void
  801. Options::checked_parse_arg
  802. (
  803. int argc,
  804. char* argv[],
  805. int& current,
  806. std::shared_ptr<OptionDetails> value,
  807. const std::string& name
  808. )
  809. {
  810. if (current + 1 >= argc)
  811. {
  812. if (value->value().has_implicit())
  813. {
  814. parse_option(value, name, "");
  815. }
  816. else
  817. {
  818. throw missing_argument_exception(name);
  819. }
  820. }
  821. else
  822. {
  823. if (argv[current + 1][0] == '-' && value->value().has_implicit())
  824. {
  825. parse_option(value, name, "");
  826. }
  827. else
  828. {
  829. parse_option(value, name, argv[current + 1]);
  830. ++current;
  831. }
  832. }
  833. }
  834. void
  835. Options::add_to_option(const std::string& option, const std::string& arg)
  836. {
  837. auto iter = m_options.find(option);
  838. if (iter == m_options.end())
  839. {
  840. throw option_not_exists_exception(option);
  841. }
  842. parse_option(iter->second, option, arg);
  843. }
  844. bool
  845. Options::consume_positional(std::string a)
  846. {
  847. if (m_positional.size() > 0)
  848. {
  849. add_to_option(m_positional, a);
  850. return true;
  851. }
  852. else
  853. {
  854. return false;
  855. }
  856. }
  857. void
  858. Options::parse_positional(std::string option)
  859. {
  860. m_positional = std::move(option);
  861. }
  862. void
  863. Options::parse(int& argc, char**& argv)
  864. {
  865. int current = 1;
  866. int nextKeep = 1;
  867. while (current != argc)
  868. {
  869. std::match_results<const char*> result;
  870. std::regex_match(argv[current], result, option_matcher);
  871. if (result.empty())
  872. {
  873. //not a flag
  874. //if true is returned here then it was consumed, otherwise it is
  875. //ignored
  876. if (consume_positional(argv[current]))
  877. {
  878. }
  879. else
  880. {
  881. argv[nextKeep] = argv[current];
  882. ++nextKeep;
  883. }
  884. //if we return from here then it was parsed successfully, so continue
  885. }
  886. else
  887. {
  888. //short or long option?
  889. if (result[4].length() != 0)
  890. {
  891. const std::string& s = result[4];
  892. for (std::size_t i = 0; i != s.size(); ++i)
  893. {
  894. std::string name(1, s[i]);
  895. auto iter = m_options.find(name);
  896. if (iter == m_options.end())
  897. {
  898. throw option_not_exists_exception(name);
  899. }
  900. auto value = iter->second;
  901. //if no argument then just add it
  902. if (!value->has_arg())
  903. {
  904. parse_option(value, name);
  905. }
  906. else
  907. {
  908. //it must be the last argument
  909. if (i + 1 == s.size())
  910. {
  911. checked_parse_arg(argc, argv, current, value, name);
  912. }
  913. else if (value->value().has_implicit())
  914. {
  915. parse_option(value, name, "");
  916. }
  917. else
  918. {
  919. //error
  920. throw option_requires_argument_exception(name);
  921. }
  922. }
  923. }
  924. }
  925. else if (result[1].length() != 0)
  926. {
  927. const std::string& name = result[1];
  928. auto iter = m_options.find(name);
  929. if (iter == m_options.end())
  930. {
  931. throw option_not_exists_exception(name);
  932. }
  933. auto opt = iter->second;
  934. //equals provided for long option?
  935. if (result[3].length() != 0)
  936. {
  937. //parse the option given
  938. //but if it doesn't take an argument, this is an error
  939. if (!opt->has_arg())
  940. {
  941. throw option_not_has_argument_exception(name, result[3]);
  942. }
  943. parse_option(opt, name, result[3]);
  944. }
  945. else
  946. {
  947. if (opt->has_arg())
  948. {
  949. //parse the next argument
  950. checked_parse_arg(argc, argv, current, opt, name);
  951. }
  952. else
  953. {
  954. //parse with empty argument
  955. parse_option(opt, name);
  956. }
  957. }
  958. }
  959. }
  960. ++current;
  961. }
  962. for (auto& opt : m_options)
  963. {
  964. auto& detail = opt.second;
  965. auto& value = detail->value();
  966. if(!detail->count() && value.has_default()){
  967. detail->parse_default();
  968. }
  969. }
  970. argc = nextKeep;
  971. }
  972. void
  973. Options::add_option
  974. (
  975. const std::string& group,
  976. const std::string& s,
  977. const std::string& l,
  978. std::string desc,
  979. std::shared_ptr<const Value> value,
  980. std::string arg_help
  981. )
  982. {
  983. auto stringDesc = toLocalString(std::move(desc));
  984. auto option = std::make_shared<OptionDetails>(stringDesc, value);
  985. if (s.size() > 0)
  986. {
  987. add_one_option(s, option);
  988. }
  989. if (l.size() > 0)
  990. {
  991. add_one_option(l, option);
  992. }
  993. //add the help details
  994. auto& options = m_help[group];
  995. options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
  996. value->has_arg(),
  997. value->has_default(), value->get_default_value(),
  998. value->has_implicit(), value->get_implicit_value(),
  999. std::move(arg_help)});
  1000. }
  1001. void
  1002. Options::add_one_option
  1003. (
  1004. const std::string& option,
  1005. std::shared_ptr<OptionDetails> details
  1006. )
  1007. {
  1008. auto in = m_options.emplace(option, details);
  1009. if (!in.second)
  1010. {
  1011. throw option_exists_error(option);
  1012. }
  1013. }
  1014. String
  1015. Options::help_one_group(const std::string& g) const
  1016. {
  1017. typedef std::vector<std::pair<String, String>> OptionHelp;
  1018. auto group = m_help.find(g);
  1019. if (group == m_help.end())
  1020. {
  1021. return "";
  1022. }
  1023. OptionHelp format;
  1024. size_t longest = 0;
  1025. String result;
  1026. if (!g.empty())
  1027. {
  1028. result += toLocalString(" " + g + " options:\n\n");
  1029. }
  1030. for (const auto& o : group->second.options)
  1031. {
  1032. auto s = format_option(o);
  1033. longest = std::max(longest, stringLength(s));
  1034. format.push_back(std::make_pair(s, String()));
  1035. }
  1036. longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));
  1037. //widest allowed description
  1038. auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
  1039. auto fiter = format.begin();
  1040. for (const auto& o : group->second.options)
  1041. {
  1042. auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
  1043. result += fiter->first;
  1044. if (stringLength(fiter->first) > longest)
  1045. {
  1046. result += "\n";
  1047. result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
  1048. }
  1049. else
  1050. {
  1051. result += toLocalString(std::string(longest + OPTION_DESC_GAP -
  1052. stringLength(fiter->first),
  1053. ' '));
  1054. }
  1055. result += d;
  1056. result += "\n";
  1057. ++fiter;
  1058. }
  1059. return result;
  1060. }
  1061. std::string
  1062. Options::help(const std::vector<std::string>& groups) const
  1063. {
  1064. String result = "Usage:\n " + toLocalString(m_program) + " [OPTION...]"
  1065. + m_help_string + "\n\n";
  1066. for (std::size_t i = 0; i < groups.size(); ++i)
  1067. {
  1068. result += help_one_group(groups[i]);
  1069. if (i < groups.size() - 1)
  1070. {
  1071. result += "\n";
  1072. }
  1073. }
  1074. return toUTF8String(result);
  1075. }
  1076. const std::vector<std::string>
  1077. Options::groups() const
  1078. {
  1079. std::vector<std::string> g;
  1080. std::transform(
  1081. m_help.begin(),
  1082. m_help.end(),
  1083. std::back_inserter(g),
  1084. [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
  1085. {
  1086. return pair.first;
  1087. }
  1088. );
  1089. return g;
  1090. }
  1091. const HelpGroupDetails&
  1092. Options::group_help(const std::string& group) const
  1093. {
  1094. return m_help.at(group);
  1095. }
  1096. }
  1097. #if defined(__GNU__)
  1098. #pragma GCC diagnostic pop
  1099. #endif
  1100. #endif //CXX_OPTS_HPP