cxxopts.hpp 28KB

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