00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef CXX_OPTS_HPP
00026 #define CXX_OPTS_HPP
00027
00028 #if defined(__GNUC__)
00029 #pragma GCC diagnostic push
00030 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
00031 #endif
00032
00033 #include <exception>
00034 #include <iostream>
00035 #include <map>
00036 #include <memory>
00037 #include <regex>
00038 #include <sstream>
00039 #include <string>
00040 #include <vector>
00041
00042
00043
00044
00045
00046
00047
00048 #ifdef CXXOPTS_USE_UNICODE
00049 #include <unicode/unistr.h>
00050
00051 namespace cxxopts
00052 {
00053 typedef icu::UnicodeString String;
00054
00055 inline
00056 String
00057 toLocalString(std::string s)
00058 {
00059 return icu::UnicodeString::fromUTF8(s);
00060 }
00061
00062 class UnicodeStringIterator : public
00063 std::iterator<std::forward_iterator_tag, int32_t>
00064 {
00065 public:
00066
00067 UnicodeStringIterator(const icu::UnicodeString* s, int32_t pos)
00068 : s(s)
00069 , i(pos)
00070 {
00071 }
00072
00073 value_type
00074 operator*() const
00075 {
00076 return s->char32At(i);
00077 }
00078
00079 bool
00080 operator==(const UnicodeStringIterator& rhs) const
00081 {
00082 return s == rhs.s && i == rhs.i;
00083 }
00084
00085 bool
00086 operator!=(const UnicodeStringIterator& rhs) const
00087 {
00088 return !(*this == rhs);
00089 }
00090
00091 UnicodeStringIterator&
00092 operator++()
00093 {
00094 ++i;
00095 return *this;
00096 }
00097
00098 UnicodeStringIterator
00099 operator+(int32_t v)
00100 {
00101 return UnicodeStringIterator(s, i + v);
00102 }
00103
00104 private:
00105 const icu::UnicodeString* s;
00106 int32_t i;
00107 };
00108
00109 inline
00110 String&
00111 stringAppend(String&s, String a)
00112 {
00113 return s.append(std::move(a));
00114 }
00115
00116 inline
00117 String&
00118 stringAppend(String& s, int n, UChar32 c)
00119 {
00120 for (int i = 0; i != n; ++i)
00121 {
00122 s.append(c);
00123 }
00124
00125 return s;
00126 }
00127
00128 template <typename Iterator>
00129 String&
00130 stringAppend(String& s, Iterator begin, Iterator end)
00131 {
00132 while (begin != end)
00133 {
00134 s.append(*begin);
00135 ++begin;
00136 }
00137
00138 return s;
00139 }
00140
00141 inline
00142 size_t
00143 stringLength(const String& s)
00144 {
00145 return s.length();
00146 }
00147
00148 inline
00149 std::string
00150 toUTF8String(const String& s)
00151 {
00152 std::string result;
00153 s.toUTF8String(result);
00154
00155 return result;
00156 }
00157 }
00158
00159 namespace std
00160 {
00161 cxxopts::UnicodeStringIterator
00162 begin(const icu::UnicodeString& s)
00163 {
00164 return cxxopts::UnicodeStringIterator(&s, 0);
00165 }
00166
00167 cxxopts::UnicodeStringIterator
00168 end(const icu::UnicodeString& s)
00169 {
00170 return cxxopts::UnicodeStringIterator(&s, s.length());
00171 }
00172 }
00173
00174
00175 #else
00176
00177 namespace cxxopts
00178 {
00179 typedef std::string String;
00180
00181 template <typename T>
00182 T
00183 toLocalString(T&& t)
00184 {
00185 return t;
00186 }
00187
00188 inline
00189 size_t
00190 stringLength(const String& s)
00191 {
00192 return s.length();
00193 }
00194
00195 inline
00196 String&
00197 stringAppend(String&s, String a)
00198 {
00199 return s.append(std::move(a));
00200 }
00201
00202 inline
00203 String&
00204 stringAppend(String& s, size_t n, char c)
00205 {
00206 return s.append(n, c);
00207 }
00208
00209 template <typename Iterator>
00210 String&
00211 stringAppend(String& s, Iterator begin, Iterator end)
00212 {
00213 return s.append(begin, end);
00214 }
00215
00216 template <typename T>
00217 std::string
00218 toUTF8String(T&& t)
00219 {
00220 return std::forward<T>(t);
00221 }
00222
00223 }
00224
00225
00226 #endif
00227
00228 namespace cxxopts
00229 {
00230 class Value : public std::enable_shared_from_this<Value>
00231 {
00232 public:
00233
00234 virtual void
00235 parse(const std::string& text) const = 0;
00236
00237 virtual void
00238 parse() const = 0;
00239
00240 virtual bool
00241 has_arg() const = 0;
00242
00243 virtual bool
00244 has_default() const = 0;
00245
00246 virtual bool
00247 has_implicit() const = 0;
00248
00249 virtual std::string
00250 get_default_value() const = 0;
00251
00252 virtual std::string
00253 get_implicit_value() const = 0;
00254
00255 virtual std::shared_ptr<Value>
00256 default_value(const std::string& value) = 0;
00257
00258 virtual std::shared_ptr<Value>
00259 implicit_value(const std::string& value) = 0;
00260 };
00261
00262 class OptionException : public std::exception
00263 {
00264 public:
00265 OptionException(const std::string& message)
00266 : m_message(message)
00267 {
00268 }
00269
00270 virtual const char*
00271 what() const noexcept
00272 {
00273 return m_message.c_str();
00274 }
00275
00276 private:
00277 std::string m_message;
00278 };
00279
00280 class OptionSpecException : public OptionException
00281 {
00282 public:
00283
00284 OptionSpecException(const std::string& message)
00285 : OptionException(message)
00286 {
00287 }
00288 };
00289
00290 class OptionParseException : public OptionException
00291 {
00292 public:
00293 OptionParseException(const std::string& message)
00294 : OptionException(message)
00295 {
00296 }
00297 };
00298
00299 class option_exists_error : public OptionSpecException
00300 {
00301 public:
00302 option_exists_error(const std::string& option)
00303 : OptionSpecException(u8"Option ‘" + option + u8"’ already exists")
00304 {
00305 }
00306 };
00307
00308 class invalid_option_format_error : public OptionSpecException
00309 {
00310 public:
00311 invalid_option_format_error(const std::string& format)
00312 : OptionSpecException(u8"Invalid option format ‘" + format + u8"’")
00313 {
00314 }
00315 };
00316
00317 class option_not_exists_exception : public OptionParseException
00318 {
00319 public:
00320 option_not_exists_exception(const std::string& option)
00321 : OptionParseException(u8"Option ‘" + option + u8"’ does not exist")
00322 {
00323 }
00324 };
00325
00326 class missing_argument_exception : public OptionParseException
00327 {
00328 public:
00329 missing_argument_exception(const std::string& option)
00330 : OptionParseException(u8"Option ‘" + option + u8"’ is missing an argument")
00331 {
00332 }
00333 };
00334
00335 class option_requires_argument_exception : public OptionParseException
00336 {
00337 public:
00338 option_requires_argument_exception(const std::string& option)
00339 : OptionParseException(u8"Option ‘" + option + u8"’ requires an argument")
00340 {
00341 }
00342 };
00343
00344 class option_not_has_argument_exception : public OptionParseException
00345 {
00346 public:
00347 option_not_has_argument_exception
00348 (
00349 const std::string& option,
00350 const std::string& arg
00351 )
00352 : OptionParseException(
00353 u8"Option ‘" + option + u8"’ does not take an argument, but argument‘"
00354 + arg + "’ given")
00355 {
00356 }
00357 };
00358
00359 class option_not_present_exception : public OptionParseException
00360 {
00361 public:
00362 option_not_present_exception(const std::string& option)
00363 : OptionParseException(u8"Option ‘" + option + u8"’ not present")
00364 {
00365 }
00366 };
00367
00368 class argument_incorrect_type : public OptionParseException
00369 {
00370 public:
00371 argument_incorrect_type
00372 (
00373 const std::string& arg
00374 )
00375 : OptionParseException(
00376 u8"Argument ‘" + arg + u8"’ failed to parse"
00377 )
00378 {
00379 }
00380 };
00381
00382 namespace values
00383 {
00384 template <typename T>
00385 void
00386 parse_value(const std::string& text, T& value)
00387 {
00388 std::istringstream is(text);
00389 if (!(is >> value))
00390 {
00391 std::cerr << "cannot parse empty value" << std::endl;
00392 throw argument_incorrect_type(text);
00393 }
00394
00395 if (is.rdbuf()->in_avail() != 0)
00396 {
00397 throw argument_incorrect_type(text);
00398 }
00399 }
00400
00401 template <typename T>
00402 void
00403 parse_value(const std::string& text, std::vector<T>& value)
00404 {
00405 T v;
00406 parse_value(text, v);
00407 value.push_back(v);
00408 }
00409
00410 inline
00411 void
00412 parse_value(const std::string& , bool& value)
00413 {
00414
00415
00416 value = true;
00417 }
00418
00419 inline
00420 void
00421 parse_value(const std::string& text, std::string& value)
00422 {
00423 value = text;
00424 }
00425
00426 template <typename T>
00427 struct value_has_arg
00428 {
00429 static constexpr bool value = true;
00430 };
00431
00432 template <>
00433 struct value_has_arg<bool>
00434 {
00435 static constexpr bool value = false;
00436 };
00437
00438 template <typename T>
00439 class standard_value : public Value
00440 {
00441 public:
00442 standard_value()
00443 : m_result(std::make_shared<T>())
00444 , m_store(m_result.get())
00445 {
00446 }
00447
00448 standard_value(T* t)
00449 : m_store(t)
00450 {
00451 }
00452
00453 void
00454 parse(const std::string& text) const
00455 {
00456 if (m_implicit && text.empty())
00457 {
00458 parse_value(m_implicit_value, *m_store);
00459 }
00460 else
00461 {
00462 parse_value(text, *m_store);
00463 }
00464 }
00465
00466 void
00467 parse() const
00468 {
00469 parse_value(m_default_value, *m_store);
00470 }
00471
00472 bool
00473 has_arg() const
00474 {
00475 return value_has_arg<T>::value;
00476 }
00477
00478 bool
00479 has_default() const
00480 {
00481 return m_default;
00482 }
00483
00484 bool
00485 has_implicit() const
00486 {
00487 return m_implicit;
00488 }
00489
00490 virtual std::shared_ptr<Value>
00491 default_value(const std::string& value){
00492 m_default = true;
00493 m_default_value = value;
00494 return shared_from_this();
00495 }
00496
00497 virtual std::shared_ptr<Value>
00498 implicit_value(const std::string& value){
00499 m_implicit = true;
00500 m_implicit_value = value;
00501 return shared_from_this();
00502 }
00503
00504 std::string
00505 get_default_value() const
00506 {
00507 return m_default_value;
00508 }
00509
00510 std::string
00511 get_implicit_value() const
00512 {
00513 return m_implicit_value;
00514 }
00515
00516 const T&
00517 get() const
00518 {
00519 if (m_store == nullptr)
00520 {
00521 return *m_result;
00522 }
00523 else
00524 {
00525 return *m_store;
00526 }
00527 }
00528
00529 protected:
00530 std::shared_ptr<T> m_result;
00531 T* m_store;
00532 bool m_default = false;
00533 std::string m_default_value;
00534 bool m_implicit = false;
00535 std::string m_implicit_value;
00536 };
00537 }
00538
00539 template <typename T>
00540 std::shared_ptr<Value>
00541 value()
00542 {
00543 return std::make_shared<values::standard_value<T>>();
00544 }
00545
00546 template <typename T>
00547 std::shared_ptr<Value>
00548 value(T& t)
00549 {
00550 return std::make_shared<values::standard_value<T>>(&t);
00551 }
00552
00553 class OptionAdder;
00554
00555 class OptionDetails
00556 {
00557 public:
00558 OptionDetails
00559 (
00560 const String& description,
00561 std::shared_ptr<const Value> value
00562 )
00563 : m_desc(description)
00564 , m_value(value)
00565 , m_count(0)
00566 {
00567 }
00568
00569 const String&
00570 description() const
00571 {
00572 return m_desc;
00573 }
00574
00575 bool
00576 has_arg() const
00577 {
00578 return m_value->has_arg();
00579 }
00580
00581 void
00582 parse(const std::string& text)
00583 {
00584 m_value->parse(text);
00585 ++m_count;
00586 }
00587
00588 void
00589 parse_default()
00590 {
00591 m_value->parse();
00592 ++m_count;
00593 }
00594
00595 int
00596 count() const
00597 {
00598 return m_count;
00599 }
00600
00601 const Value& value() const {
00602 return *m_value;
00603 }
00604
00605 template <typename T>
00606 const T&
00607 as() const
00608 {
00609 #ifdef CXXOPTS_NO_RTTI
00610 return static_cast<const values::standard_value<T>&>(*m_value).get();
00611 #else
00612 return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
00613 #endif
00614 }
00615
00616 private:
00617 String m_desc;
00618 std::shared_ptr<const Value> m_value;
00619 int m_count;
00620 };
00621
00622 struct HelpOptionDetails
00623 {
00624 std::string s;
00625 std::string l;
00626 String desc;
00627 bool has_arg;
00628 bool has_default;
00629 std::string default_value;
00630 bool has_implicit;
00631 std::string implicit_value;
00632 std::string arg_help;
00633 };
00634
00635 struct HelpGroupDetails
00636 {
00637 std::string name;
00638 std::string description;
00639 std::vector<HelpOptionDetails> options;
00640 };
00641
00642 class Options
00643 {
00644 public:
00645
00646 Options(std::string program, std::string help_string = "")
00647 : m_program(std::move(program))
00648 , m_help_string(toLocalString(std::move(help_string)))
00649 {
00650 }
00651
00652 inline
00653 void
00654 parse(int& argc, char**& argv);
00655
00656 inline
00657 OptionAdder
00658 add_options(std::string group = "");
00659
00660 inline
00661 void
00662 add_option
00663 (
00664 const std::string& group,
00665 const std::string& s,
00666 const std::string& l,
00667 std::string desc,
00668 std::shared_ptr<const Value> value,
00669 std::string arg_help
00670 );
00671
00672 int
00673 count(const std::string& o) const
00674 {
00675 auto iter = m_options.find(o);
00676 if (iter == m_options.end())
00677 {
00678 return 0;
00679 }
00680
00681 return iter->second->count();
00682 }
00683
00684 const OptionDetails&
00685 operator[](const std::string& option) const
00686 {
00687 auto iter = m_options.find(option);
00688
00689 if (iter == m_options.end())
00690 {
00691 throw option_not_present_exception(option);
00692 }
00693
00694 return *iter->second;
00695 }
00696
00697
00698 inline
00699 void
00700 parse_positional(std::string option);
00701
00702 inline
00703 std::string
00704 help(const std::vector<std::string>& groups = {""}) const;
00705
00706 inline
00707 const std::vector<std::string>
00708 groups() const;
00709
00710 inline
00711 const HelpGroupDetails&
00712 group_help(const std::string& group) const;
00713
00714 private:
00715
00716 inline
00717 void
00718 add_one_option
00719 (
00720 const std::string& option,
00721 std::shared_ptr<OptionDetails> details
00722 );
00723
00724 inline
00725 bool
00726 consume_positional(std::string a);
00727
00728 inline
00729 void
00730 add_to_option(const std::string& option, const std::string& arg);
00731
00732 inline
00733 void
00734 parse_option
00735 (
00736 std::shared_ptr<OptionDetails> value,
00737 const std::string& name,
00738 const std::string& arg = ""
00739 );
00740
00741 inline
00742 void
00743 checked_parse_arg
00744 (
00745 int argc,
00746 char* argv[],
00747 int& current,
00748 std::shared_ptr<OptionDetails> value,
00749 const std::string& name
00750 );
00751
00752 inline
00753 String
00754 help_one_group(const std::string& group) const;
00755
00756 std::string m_program;
00757 String m_help_string;
00758
00759 std::map<std::string, std::shared_ptr<OptionDetails>> m_options;
00760 std::string m_positional;
00761
00762
00763 std::map<std::string, HelpGroupDetails> m_help;
00764 };
00765
00766 class OptionAdder
00767 {
00768 public:
00769
00770 OptionAdder(Options& options, std::string group)
00771 : m_options(options), m_group(std::move(group))
00772 {
00773 }
00774
00775 inline
00776 OptionAdder&
00777 operator()
00778 (
00779 const std::string& opts,
00780 const std::string& desc,
00781 std::shared_ptr<const Value> value
00782 = ::cxxopts::value<bool>(),
00783 std::string arg_help = ""
00784 );
00785
00786 private:
00787 Options& m_options;
00788 std::string m_group;
00789 };
00790
00791 }
00792
00793 namespace cxxopts
00794 {
00795
00796 namespace
00797 {
00798
00799 constexpr int OPTION_LONGEST = 30;
00800 constexpr int OPTION_DESC_GAP = 2;
00801
00802 std::basic_regex<char> option_matcher
00803 ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([a-zA-Z]+)");
00804
00805 std::basic_regex<char> option_specifier
00806 ("(([a-zA-Z]),)?([a-zA-Z0-9][-_a-zA-Z0-9]+)");
00807
00808 String
00809 format_option
00810 (
00811 const HelpOptionDetails& o
00812 )
00813 {
00814 auto& s = o.s;
00815 auto& l = o.l;
00816
00817 String result = " ";
00818
00819 if (s.size() > 0)
00820 {
00821 result += "-" + toLocalString(s) + ",";
00822 }
00823 else
00824 {
00825 result += " ";
00826 }
00827
00828 if (l.size() > 0)
00829 {
00830 result += " --" + toLocalString(l);
00831 }
00832
00833 if (o.has_arg)
00834 {
00835 auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
00836
00837 if (o.has_implicit)
00838 {
00839 result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
00840 }
00841 else
00842 {
00843 result += " " + arg;
00844 }
00845 }
00846
00847 return result;
00848 }
00849
00850 String
00851 format_description
00852 (
00853 const HelpOptionDetails& o,
00854 size_t start,
00855 size_t width
00856 )
00857 {
00858 auto desc = o.desc;
00859
00860 if (o.has_default)
00861 {
00862 desc += toLocalString(" (default:" + o.default_value + ")");
00863 }
00864
00865 String result;
00866
00867 auto current = std::begin(desc);
00868 auto startLine = current;
00869 auto lastSpace = current;
00870
00871 auto size = size_t{};
00872
00873 while (current != std::end(desc))
00874 {
00875 if (*current == ' ')
00876 {
00877 lastSpace = current;
00878 }
00879
00880 if (size > width)
00881 {
00882 if (lastSpace == startLine)
00883 {
00884 stringAppend(result, startLine, current + 1);
00885 stringAppend(result, "\n");
00886 stringAppend(result, start, ' ');
00887 startLine = current + 1;
00888 lastSpace = startLine;
00889 }
00890 else
00891 {
00892 stringAppend(result, startLine, lastSpace);
00893 stringAppend(result, "\n");
00894 stringAppend(result, start, ' ');
00895 startLine = lastSpace + 1;
00896 }
00897 size = 0;
00898 }
00899 else
00900 {
00901 ++size;
00902 }
00903
00904 ++current;
00905 }
00906
00907
00908 stringAppend(result, startLine, current);
00909
00910 return result;
00911 }
00912 }
00913
00914 OptionAdder
00915 Options::add_options(std::string group)
00916 {
00917 return OptionAdder(*this, std::move(group));
00918 }
00919
00920 OptionAdder&
00921 OptionAdder::operator()
00922 (
00923 const std::string& opts,
00924 const std::string& desc,
00925 std::shared_ptr<const Value> value,
00926 std::string arg_help
00927 )
00928 {
00929 std::match_results<const char*> result;
00930 std::regex_match(opts.c_str(), result, option_specifier);
00931
00932 if (result.empty())
00933 {
00934 throw invalid_option_format_error(opts);
00935 }
00936
00937 const auto& s = result[2];
00938 const auto& l = result[3];
00939
00940 m_options.add_option(m_group, s.str(), l.str(), desc, value,
00941 std::move(arg_help));
00942
00943 return *this;
00944 }
00945
00946 void
00947 Options::parse_option
00948 (
00949 std::shared_ptr<OptionDetails> value,
00950 const std::string& ,
00951 const std::string& arg
00952 )
00953 {
00954 value->parse(arg);
00955 }
00956
00957 void
00958 Options::checked_parse_arg
00959 (
00960 int argc,
00961 char* argv[],
00962 int& current,
00963 std::shared_ptr<OptionDetails> value,
00964 const std::string& name
00965 )
00966 {
00967 if (current + 1 >= argc)
00968 {
00969 if (value->value().has_implicit())
00970 {
00971 parse_option(value, name, "");
00972 }
00973 else
00974 {
00975 throw missing_argument_exception(name);
00976 }
00977 }
00978 else
00979 {
00980 if (argv[current + 1][0] == '-' && value->value().has_implicit())
00981 {
00982 parse_option(value, name, "");
00983 }
00984 else
00985 {
00986 parse_option(value, name, argv[current + 1]);
00987 ++current;
00988 }
00989 }
00990 }
00991
00992 void
00993 Options::add_to_option(const std::string& option, const std::string& arg)
00994 {
00995 auto iter = m_options.find(option);
00996
00997 if (iter == m_options.end())
00998 {
00999 throw option_not_exists_exception(option);
01000 }
01001
01002 parse_option(iter->second, option, arg);
01003 }
01004
01005 bool
01006 Options::consume_positional(std::string a)
01007 {
01008 if (m_positional.size() > 0)
01009 {
01010 add_to_option(m_positional, a);
01011 return true;
01012 }
01013 else
01014 {
01015 return false;
01016 }
01017 }
01018
01019 void
01020 Options::parse_positional(std::string option)
01021 {
01022 m_positional = std::move(option);
01023 }
01024
01025 void
01026 Options::parse(int& argc, char**& argv)
01027 {
01028 int current = 1;
01029
01030 int nextKeep = 1;
01031
01032 while (current != argc)
01033 {
01034 std::match_results<const char*> result;
01035 std::regex_match(argv[current], result, option_matcher);
01036
01037 if (result.empty())
01038 {
01039
01040
01041
01042
01043 if (consume_positional(argv[current]))
01044 {
01045 }
01046 else
01047 {
01048 argv[nextKeep] = argv[current];
01049 ++nextKeep;
01050 }
01051
01052 }
01053 else
01054 {
01055
01056 if (result[4].length() != 0)
01057 {
01058 const std::string& s = result[4];
01059
01060 for (std::size_t i = 0; i != s.size(); ++i)
01061 {
01062 std::string name(1, s[i]);
01063 auto iter = m_options.find(name);
01064
01065 if (iter == m_options.end())
01066 {
01067 throw option_not_exists_exception(name);
01068 }
01069
01070 auto value = iter->second;
01071
01072
01073 if (!value->has_arg())
01074 {
01075 parse_option(value, name);
01076 }
01077 else
01078 {
01079
01080 if (i + 1 == s.size())
01081 {
01082 checked_parse_arg(argc, argv, current, value, name);
01083 }
01084 else if (value->value().has_implicit())
01085 {
01086 parse_option(value, name, "");
01087 }
01088 else
01089 {
01090
01091 throw option_requires_argument_exception(name);
01092 }
01093 }
01094 }
01095 }
01096 else if (result[1].length() != 0)
01097 {
01098 const std::string& name = result[1];
01099
01100 auto iter = m_options.find(name);
01101
01102 if (iter == m_options.end())
01103 {
01104 throw option_not_exists_exception(name);
01105 }
01106
01107 auto opt = iter->second;
01108
01109
01110 if (result[3].length() != 0)
01111 {
01112
01113
01114
01115 if (!opt->has_arg())
01116 {
01117 throw option_not_has_argument_exception(name, result[3]);
01118 }
01119
01120 parse_option(opt, name, result[3]);
01121 }
01122 else
01123 {
01124 if (opt->has_arg())
01125 {
01126
01127 checked_parse_arg(argc, argv, current, opt, name);
01128 }
01129 else
01130 {
01131
01132 parse_option(opt, name);
01133 }
01134 }
01135 }
01136
01137 }
01138
01139 ++current;
01140 }
01141
01142 for (auto& opt : m_options)
01143 {
01144 auto& detail = opt.second;
01145 auto& value = detail->value();
01146
01147 if(!detail->count() && value.has_default()){
01148 detail->parse_default();
01149 }
01150 }
01151
01152 argc = nextKeep;
01153 }
01154
01155 void
01156 Options::add_option
01157 (
01158 const std::string& group,
01159 const std::string& s,
01160 const std::string& l,
01161 std::string desc,
01162 std::shared_ptr<const Value> value,
01163 std::string arg_help
01164 )
01165 {
01166 auto stringDesc = toLocalString(std::move(desc));
01167 auto option = std::make_shared<OptionDetails>(stringDesc, value);
01168
01169 if (s.size() > 0)
01170 {
01171 add_one_option(s, option);
01172 }
01173
01174 if (l.size() > 0)
01175 {
01176 add_one_option(l, option);
01177 }
01178
01179
01180 auto& options = m_help[group];
01181
01182 options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
01183 value->has_arg(),
01184 value->has_default(), value->get_default_value(),
01185 value->has_implicit(), value->get_implicit_value(),
01186 std::move(arg_help)});
01187 }
01188
01189 void
01190 Options::add_one_option
01191 (
01192 const std::string& option,
01193 std::shared_ptr<OptionDetails> details
01194 )
01195 {
01196 auto in = m_options.emplace(option, details);
01197
01198 if (!in.second)
01199 {
01200 throw option_exists_error(option);
01201 }
01202 }
01203
01204 String
01205 Options::help_one_group(const std::string& g) const
01206 {
01207 typedef std::vector<std::pair<String, String>> OptionHelp;
01208
01209 auto group = m_help.find(g);
01210 if (group == m_help.end())
01211 {
01212 return "";
01213 }
01214
01215 OptionHelp format;
01216
01217 size_t longest = 0;
01218
01219 String result;
01220
01221 if (!g.empty())
01222 {
01223 result += toLocalString(" " + g + " options:\n\n");
01224 }
01225
01226 for (const auto& o : group->second.options)
01227 {
01228 auto s = format_option(o);
01229 longest = std::max(longest, stringLength(s));
01230 format.push_back(std::make_pair(s, String()));
01231 }
01232
01233 longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));
01234
01235
01236 auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
01237
01238 auto fiter = format.begin();
01239 for (const auto& o : group->second.options)
01240 {
01241 auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
01242
01243 result += fiter->first;
01244 if (stringLength(fiter->first) > longest)
01245 {
01246 result += "\n";
01247 result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
01248 }
01249 else
01250 {
01251 result += toLocalString(std::string(longest + OPTION_DESC_GAP -
01252 stringLength(fiter->first),
01253 ' '));
01254 }
01255 result += d;
01256 result += "\n";
01257
01258 ++fiter;
01259 }
01260
01261 return result;
01262 }
01263
01264 std::string
01265 Options::help(const std::vector<std::string>& groups) const
01266 {
01267 String result = "Usage:\n " + toLocalString(m_program) + " [OPTION...]"
01268 + m_help_string + "\n\n";
01269
01270 for (std::size_t i = 0; i < groups.size(); ++i)
01271 {
01272 result += help_one_group(groups[i]);
01273 if (i < groups.size() - 1)
01274 {
01275 result += "\n";
01276 }
01277 }
01278
01279 return toUTF8String(result);
01280 }
01281
01282 const std::vector<std::string>
01283 Options::groups() const
01284 {
01285 std::vector<std::string> g;
01286
01287 std::transform(
01288 m_help.begin(),
01289 m_help.end(),
01290 std::back_inserter(g),
01291 [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
01292 {
01293 return pair.first;
01294 }
01295 );
01296
01297 return g;
01298 }
01299
01300 const HelpGroupDetails&
01301 Options::group_help(const std::string& group) const
01302 {
01303 return m_help.at(group);
01304 }
01305
01306 }
01307
01308 #if defined(__GNU__)
01309 #pragma GCC diagnostic pop
01310 #endif
01311
01312 #endif //CXX_OPTS_HPP