nmeadump: basic version of nmeadump added.
[marnav.git] / extern / cxxopts / cxxopts.hpp
blobd7b0f68d339992ed3454a19847d607a48c1fd99e
1 /*
3 Copyright (c) 2014, 2015, 2016 Jarryd Beck
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 THE SOFTWARE.
25 #ifndef CXX_OPTS_HPP
26 #define CXX_OPTS_HPP
28 #if defined(__GNUC__)
29 #pragma GCC diagnostic push
30 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
31 #endif
33 #include <cstring>
34 #include <exception>
35 #include <iostream>
36 #include <map>
37 #include <memory>
38 #include <regex>
39 #include <sstream>
40 #include <string>
41 #include <unordered_set>
42 #include <vector>
44 //when we ask cxxopts to use Unicode, help strings are processed using ICU,
45 //which results in the correct lengths being computed for strings when they
46 //are formatted for the help output
47 //it is necessary to make sure that <unicode/unistr.h> can be found by the
48 //compiler, and that icu-uc is linked in to the binary.
50 #ifdef CXXOPTS_USE_UNICODE
51 #include <unicode/unistr.h>
53 namespace cxxopts
55 typedef icu::UnicodeString String;
57 inline
58 String
59 toLocalString(std::string s)
61 return icu::UnicodeString::fromUTF8(s);
64 class UnicodeStringIterator : public
65 std::iterator<std::forward_iterator_tag, int32_t>
67 public:
69 UnicodeStringIterator(const icu::UnicodeString* s, int32_t pos)
70 : s(s)
71 , i(pos)
75 value_type
76 operator*() const
78 return s->char32At(i);
81 bool
82 operator==(const UnicodeStringIterator& rhs) const
84 return s == rhs.s && i == rhs.i;
87 bool
88 operator!=(const UnicodeStringIterator& rhs) const
90 return !(*this == rhs);
93 UnicodeStringIterator&
94 operator++()
96 ++i;
97 return *this;
100 UnicodeStringIterator
101 operator+(int32_t v)
103 return UnicodeStringIterator(s, i + v);
106 private:
107 const icu::UnicodeString* s;
108 int32_t i;
111 inline
112 String&
113 stringAppend(String&s, String a)
115 return s.append(std::move(a));
118 inline
119 String&
120 stringAppend(String& s, int n, UChar32 c)
122 for (int i = 0; i != n; ++i)
124 s.append(c);
127 return s;
130 template <typename Iterator>
131 String&
132 stringAppend(String& s, Iterator begin, Iterator end)
134 while (begin != end)
136 s.append(*begin);
137 ++begin;
140 return s;
143 inline
144 size_t
145 stringLength(const String& s)
147 return s.length();
150 inline
151 std::string
152 toUTF8String(const String& s)
154 std::string result;
155 s.toUTF8String(result);
157 return result;
161 namespace std
163 cxxopts::UnicodeStringIterator
164 begin(const icu::UnicodeString& s)
166 return cxxopts::UnicodeStringIterator(&s, 0);
169 cxxopts::UnicodeStringIterator
170 end(const icu::UnicodeString& s)
172 return cxxopts::UnicodeStringIterator(&s, s.length());
176 //ifdef CXXOPTS_USE_UNICODE
177 #else
179 namespace cxxopts
181 typedef std::string String;
183 template <typename T>
185 toLocalString(T&& t)
187 return t;
190 inline
191 size_t
192 stringLength(const String& s)
194 return s.length();
197 inline
198 String&
199 stringAppend(String&s, String a)
201 return s.append(std::move(a));
204 inline
205 String&
206 stringAppend(String& s, size_t n, char c)
208 return s.append(n, c);
211 template <typename Iterator>
212 String&
213 stringAppend(String& s, Iterator begin, Iterator end)
215 return s.append(begin, end);
218 template <typename T>
219 std::string
220 toUTF8String(T&& t)
222 return std::forward<T>(t);
227 //ifdef CXXOPTS_USE_UNICODE
228 #endif
230 namespace cxxopts
232 class Value : public std::enable_shared_from_this<Value>
234 public:
236 virtual void
237 parse(const std::string& text) const = 0;
239 virtual void
240 parse() const = 0;
242 virtual bool
243 has_arg() const = 0;
245 virtual bool
246 has_default() const = 0;
248 virtual bool
249 is_container() const = 0;
251 virtual bool
252 has_implicit() const = 0;
254 virtual std::string
255 get_default_value() const = 0;
257 virtual std::string
258 get_implicit_value() const = 0;
260 virtual std::shared_ptr<Value>
261 default_value(const std::string& value) = 0;
263 virtual std::shared_ptr<Value>
264 implicit_value(const std::string& value) = 0;
267 class OptionException : public std::exception
269 public:
270 OptionException(const std::string& message)
271 : m_message(message)
275 virtual const char*
276 what() const noexcept
278 return m_message.c_str();
281 private:
282 std::string m_message;
285 class OptionSpecException : public OptionException
287 public:
289 OptionSpecException(const std::string& message)
290 : OptionException(message)
295 class OptionParseException : public OptionException
297 public:
298 OptionParseException(const std::string& message)
299 : OptionException(message)
304 class option_exists_error : public OptionSpecException
306 public:
307 option_exists_error(const std::string& option)
308 : OptionSpecException(u8"Option ‘" + option + u8"’ already exists")
313 class invalid_option_format_error : public OptionSpecException
315 public:
316 invalid_option_format_error(const std::string& format)
317 : OptionSpecException(u8"Invalid option format ‘" + format + u8"’")
322 class option_not_exists_exception : public OptionParseException
324 public:
325 option_not_exists_exception(const std::string& option)
326 : OptionParseException(u8"Option ‘" + option + u8"’ does not exist")
331 class missing_argument_exception : public OptionParseException
333 public:
334 missing_argument_exception(const std::string& option)
335 : OptionParseException(u8"Option ‘" + option + u8"’ is missing an argument")
340 class option_requires_argument_exception : public OptionParseException
342 public:
343 option_requires_argument_exception(const std::string& option)
344 : OptionParseException(u8"Option ‘" + option + u8"’ requires an argument")
349 class option_not_has_argument_exception : public OptionParseException
351 public:
352 option_not_has_argument_exception
354 const std::string& option,
355 const std::string& arg
357 : OptionParseException(
358 u8"Option ‘" + option + u8"’ does not take an argument, but argument‘"
359 + arg + "’ given")
364 class option_not_present_exception : public OptionParseException
366 public:
367 option_not_present_exception(const std::string& option)
368 : OptionParseException(u8"Option ‘" + option + u8"’ not present")
373 class argument_incorrect_type : public OptionParseException
375 public:
376 argument_incorrect_type
378 const std::string& arg
380 : OptionParseException(
381 u8"Argument ‘" + arg + u8"’ failed to parse"
387 namespace values
389 template <typename T>
390 void
391 parse_value(const std::string& text, T& value)
393 std::istringstream is(text);
394 if (!(is >> value))
396 throw argument_incorrect_type(text);
399 if (is.rdbuf()->in_avail() != 0)
401 throw argument_incorrect_type(text);
405 inline
406 void
407 parse_value(const std::string& /*text*/, bool& value)
409 //TODO recognise on, off, yes, no, enable, disable
410 //so that we can write --long=yes explicitly
411 value = true;
414 inline
415 void
416 parse_value(const std::string& text, std::string& value)
418 value = text;
421 template <typename T>
422 void
423 parse_value(const std::string& text, std::vector<T>& value)
425 T v;
426 parse_value(text, v);
427 value.push_back(v);
430 template <typename T>
431 struct value_has_arg
433 static constexpr bool value = true;
436 template <>
437 struct value_has_arg<bool>
439 static constexpr bool value = false;
442 template <typename T>
443 struct type_is_container
445 static constexpr bool value = false;
448 template <typename T>
449 struct type_is_container<std::vector<T>>
451 static constexpr bool value = true;
454 template <typename T>
455 class standard_value : public Value
457 public:
458 standard_value()
459 : m_result(std::make_shared<T>())
460 , m_store(m_result.get())
464 standard_value(T* t)
465 : m_store(t)
469 void
470 parse(const std::string& text) const
472 if (m_implicit && text.empty())
474 parse_value(m_implicit_value, *m_store);
476 else
478 parse_value(text, *m_store);
482 bool
483 is_container() const
485 return type_is_container<T>::value;
488 void
489 parse() const
491 parse_value(m_default_value, *m_store);
494 bool
495 has_arg() const
497 return value_has_arg<T>::value;
500 bool
501 has_default() const
503 return m_default;
506 bool
507 has_implicit() const
509 return m_implicit;
512 virtual std::shared_ptr<Value>
513 default_value(const std::string& value){
514 m_default = true;
515 m_default_value = value;
516 return shared_from_this();
519 virtual std::shared_ptr<Value>
520 implicit_value(const std::string& value){
521 m_implicit = true;
522 m_implicit_value = value;
523 return shared_from_this();
526 std::string
527 get_default_value() const
529 return m_default_value;
532 std::string
533 get_implicit_value() const
535 return m_implicit_value;
538 const T&
539 get() const
541 if (m_store == nullptr)
543 return *m_result;
545 else
547 return *m_store;
551 protected:
552 std::shared_ptr<T> m_result;
553 T* m_store;
554 bool m_default = false;
555 std::string m_default_value;
556 bool m_implicit = false;
557 std::string m_implicit_value;
561 template <typename T>
562 std::shared_ptr<Value>
563 value()
565 return std::make_shared<values::standard_value<T>>();
568 template <typename T>
569 std::shared_ptr<Value>
570 value(T& t)
572 return std::make_shared<values::standard_value<T>>(&t);
575 class OptionAdder;
577 class OptionDetails
579 public:
580 OptionDetails
582 const String& description,
583 std::shared_ptr<const Value> value
585 : m_desc(description)
586 , m_value(value)
587 , m_count(0)
591 const String&
592 description() const
594 return m_desc;
597 bool
598 has_arg() const
600 return m_value->has_arg();
603 void
604 parse(const std::string& text)
606 m_value->parse(text);
607 ++m_count;
610 void
611 parse_default()
613 m_value->parse();
617 count() const
619 return m_count;
622 const Value& value() const {
623 return *m_value;
626 template <typename T>
627 const T&
628 as() const
630 #ifdef CXXOPTS_NO_RTTI
631 return static_cast<const values::standard_value<T>&>(*m_value).get();
632 #else
633 return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
634 #endif
637 private:
638 String m_desc;
639 std::shared_ptr<const Value> m_value;
640 int m_count;
643 struct HelpOptionDetails
645 std::string s;
646 std::string l;
647 String desc;
648 bool has_arg;
649 bool has_default;
650 std::string default_value;
651 bool has_implicit;
652 std::string implicit_value;
653 std::string arg_help;
654 bool is_container;
657 struct HelpGroupDetails
659 std::string name;
660 std::string description;
661 std::vector<HelpOptionDetails> options;
664 class Options
666 public:
668 Options(std::string program, std::string help_string = "")
669 : m_program(std::move(program))
670 , m_help_string(toLocalString(std::move(help_string)))
671 , m_next_positional(m_positional.end())
675 inline
676 void
677 parse(int& argc, char**& argv);
679 inline
680 OptionAdder
681 add_options(std::string group = "");
683 inline
684 void
685 add_option
687 const std::string& group,
688 const std::string& s,
689 const std::string& l,
690 std::string desc,
691 std::shared_ptr<const Value> value,
692 std::string arg_help
696 count(const std::string& o) const
698 auto iter = m_options.find(o);
699 if (iter == m_options.end())
701 return 0;
704 return iter->second->count();
707 const OptionDetails&
708 operator[](const std::string& option) const
710 auto iter = m_options.find(option);
712 if (iter == m_options.end())
714 throw option_not_present_exception(option);
717 return *iter->second;
720 //parse positional arguments into the given option
721 inline
722 void
723 parse_positional(std::string option);
725 inline
726 void
727 parse_positional(std::vector<std::string> options);
729 inline
730 std::string
731 help(const std::vector<std::string>& groups = {""}) const;
733 inline
734 const std::vector<std::string>
735 groups() const;
737 inline
738 const HelpGroupDetails&
739 group_help(const std::string& group) const;
741 private:
743 inline
744 void
745 add_one_option
747 const std::string& option,
748 std::shared_ptr<OptionDetails> details
751 inline
752 bool
753 consume_positional(std::string a);
755 inline
756 void
757 add_to_option(const std::string& option, const std::string& arg);
759 inline
760 void
761 parse_option
763 std::shared_ptr<OptionDetails> value,
764 const std::string& name,
765 const std::string& arg = ""
768 inline
769 void
770 checked_parse_arg
772 int argc,
773 char* argv[],
774 int& current,
775 std::shared_ptr<OptionDetails> value,
776 const std::string& name
779 inline
780 String
781 help_one_group(const std::string& group) const;
783 std::string m_program;
784 String m_help_string;
786 std::map<std::string, std::shared_ptr<OptionDetails>> m_options;
787 std::vector<std::string> m_positional;
788 std::vector<std::string>::iterator m_next_positional;
789 std::unordered_set<std::string> m_positional_set;
791 //mapping from groups to help options
792 std::map<std::string, HelpGroupDetails> m_help;
795 class OptionAdder
797 public:
799 OptionAdder(Options& options, std::string group)
800 : m_options(options), m_group(std::move(group))
804 inline
805 OptionAdder&
806 operator()
808 const std::string& opts,
809 const std::string& desc,
810 std::shared_ptr<const Value> value
811 = ::cxxopts::value<bool>(),
812 std::string arg_help = ""
815 private:
816 Options& m_options;
817 std::string m_group;
822 namespace cxxopts
825 namespace
828 constexpr int OPTION_LONGEST = 30;
829 constexpr int OPTION_DESC_GAP = 2;
831 std::basic_regex<char> option_matcher
832 ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([a-zA-Z]+)");
834 std::basic_regex<char> option_specifier
835 ("(([a-zA-Z]),)?([a-zA-Z0-9][-_a-zA-Z0-9]+)");
837 String
838 format_option
840 const HelpOptionDetails& o
843 auto& s = o.s;
844 auto& l = o.l;
846 String result = " ";
848 if (s.size() > 0)
850 result += "-" + toLocalString(s) + ",";
852 else
854 result += " ";
857 if (l.size() > 0)
859 result += " --" + toLocalString(l);
862 if (o.has_arg)
864 auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
866 if (o.has_implicit)
868 result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
870 else
872 result += " " + arg;
876 return result;
879 String
880 format_description
882 const HelpOptionDetails& o,
883 size_t start,
884 size_t width
887 auto desc = o.desc;
889 if (o.has_default)
891 desc += toLocalString(" (default: " + o.default_value + ")");
894 String result;
896 auto current = std::begin(desc);
897 auto startLine = current;
898 auto lastSpace = current;
900 auto size = size_t{};
902 while (current != std::end(desc))
904 if (*current == ' ')
906 lastSpace = current;
909 if (size > width)
911 if (lastSpace == startLine)
913 stringAppend(result, startLine, current + 1);
914 stringAppend(result, "\n");
915 stringAppend(result, start, ' ');
916 startLine = current + 1;
917 lastSpace = startLine;
919 else
921 stringAppend(result, startLine, lastSpace);
922 stringAppend(result, "\n");
923 stringAppend(result, start, ' ');
924 startLine = lastSpace + 1;
926 size = 0;
928 else
930 ++size;
933 ++current;
936 //append whatever is left
937 stringAppend(result, startLine, current);
939 return result;
943 OptionAdder
944 Options::add_options(std::string group)
946 return OptionAdder(*this, std::move(group));
949 OptionAdder&
950 OptionAdder::operator()
952 const std::string& opts,
953 const std::string& desc,
954 std::shared_ptr<const Value> value,
955 std::string arg_help
958 std::match_results<const char*> result;
959 std::regex_match(opts.c_str(), result, option_specifier);
961 if (result.empty())
963 throw invalid_option_format_error(opts);
966 const auto& s = result[2];
967 const auto& l = result[3];
969 m_options.add_option(m_group, s.str(), l.str(), desc, value,
970 std::move(arg_help));
972 return *this;
975 void
976 Options::parse_option
978 std::shared_ptr<OptionDetails> value,
979 const std::string& /*name*/,
980 const std::string& arg
983 value->parse(arg);
986 void
987 Options::checked_parse_arg
989 int argc,
990 char* argv[],
991 int& current,
992 std::shared_ptr<OptionDetails> value,
993 const std::string& name
996 if (current + 1 >= argc)
998 if (value->value().has_implicit())
1000 parse_option(value, name, "");
1002 else
1004 throw missing_argument_exception(name);
1007 else
1009 if (argv[current + 1][0] == '-' && value->value().has_implicit())
1011 parse_option(value, name, "");
1013 else
1015 parse_option(value, name, argv[current + 1]);
1016 ++current;
1021 void
1022 Options::add_to_option(const std::string& option, const std::string& arg)
1024 auto iter = m_options.find(option);
1026 if (iter == m_options.end())
1028 throw option_not_exists_exception(option);
1031 parse_option(iter->second, option, arg);
1034 bool
1035 Options::consume_positional(std::string a)
1037 while (m_next_positional != m_positional.end())
1039 auto iter = m_options.find(*m_next_positional);
1040 if (iter != m_options.end())
1042 if (!iter->second->value().is_container())
1044 if (iter->second->count() == 0)
1046 add_to_option(*m_next_positional, a);
1047 ++m_next_positional;
1048 return true;
1050 else
1052 ++m_next_positional;
1053 continue;
1056 else
1058 add_to_option(*m_next_positional, a);
1059 return true;
1062 ++m_next_positional;
1065 return false;
1068 void
1069 Options::parse_positional(std::string option)
1071 parse_positional(std::vector<std::string>{option});
1074 void
1075 Options::parse_positional(std::vector<std::string> options)
1077 m_positional = std::move(options);
1078 m_next_positional = m_positional.begin();
1080 m_positional_set.insert(m_positional.begin(), m_positional.end());
1083 void
1084 Options::parse(int& argc, char**& argv)
1086 int current = 1;
1088 int nextKeep = 1;
1090 bool consume_remaining = false;
1092 while (current != argc)
1094 if (strcmp(argv[current], "--") == 0)
1096 consume_remaining = true;
1097 ++current;
1098 break;
1101 std::match_results<const char*> result;
1102 std::regex_match(argv[current], result, option_matcher);
1104 if (result.empty())
1106 //not a flag
1108 //if true is returned here then it was consumed, otherwise it is
1109 //ignored
1110 if (consume_positional(argv[current]))
1113 else
1115 argv[nextKeep] = argv[current];
1116 ++nextKeep;
1118 //if we return from here then it was parsed successfully, so continue
1120 else
1122 //short or long option?
1123 if (result[4].length() != 0)
1125 const std::string& s = result[4];
1127 for (std::size_t i = 0; i != s.size(); ++i)
1129 std::string name(1, s[i]);
1130 auto iter = m_options.find(name);
1132 if (iter == m_options.end())
1134 throw option_not_exists_exception(name);
1137 auto value = iter->second;
1139 //if no argument then just add it
1140 if (!value->has_arg())
1142 parse_option(value, name);
1144 else
1146 //it must be the last argument
1147 if (i + 1 == s.size())
1149 checked_parse_arg(argc, argv, current, value, name);
1151 else if (value->value().has_implicit())
1153 parse_option(value, name, "");
1155 else
1157 //error
1158 throw option_requires_argument_exception(name);
1163 else if (result[1].length() != 0)
1165 const std::string& name = result[1];
1167 auto iter = m_options.find(name);
1169 if (iter == m_options.end())
1171 throw option_not_exists_exception(name);
1174 auto opt = iter->second;
1176 //equals provided for long option?
1177 if (result[3].length() != 0)
1179 //parse the option given
1181 //but if it doesn't take an argument, this is an error
1182 if (!opt->has_arg())
1184 throw option_not_has_argument_exception(name, result[3]);
1187 parse_option(opt, name, result[3]);
1189 else
1191 if (opt->has_arg())
1193 //parse the next argument
1194 checked_parse_arg(argc, argv, current, opt, name);
1196 else
1198 //parse with empty argument
1199 parse_option(opt, name);
1206 ++current;
1209 for (auto& opt : m_options)
1211 auto& detail = opt.second;
1212 auto& value = detail->value();
1214 if(!detail->count() && value.has_default()){
1215 detail->parse_default();
1219 if (consume_remaining)
1221 while (current < argc)
1223 consume_positional(argv[current]);
1224 ++current;
1228 argc = nextKeep;
1232 void
1233 Options::add_option
1235 const std::string& group,
1236 const std::string& s,
1237 const std::string& l,
1238 std::string desc,
1239 std::shared_ptr<const Value> value,
1240 std::string arg_help
1243 auto stringDesc = toLocalString(std::move(desc));
1244 auto option = std::make_shared<OptionDetails>(stringDesc, value);
1246 if (s.size() > 0)
1248 add_one_option(s, option);
1251 if (l.size() > 0)
1253 add_one_option(l, option);
1256 //add the help details
1257 auto& options = m_help[group];
1259 options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
1260 value->has_arg(),
1261 value->has_default(), value->get_default_value(),
1262 value->has_implicit(), value->get_implicit_value(),
1263 std::move(arg_help),
1264 value->is_container()});
1267 void
1268 Options::add_one_option
1270 const std::string& option,
1271 std::shared_ptr<OptionDetails> details
1274 auto in = m_options.emplace(option, details);
1276 if (!in.second)
1278 throw option_exists_error(option);
1282 String
1283 Options::help_one_group(const std::string& g) const
1285 typedef std::vector<std::pair<String, String>> OptionHelp;
1287 auto group = m_help.find(g);
1288 if (group == m_help.end())
1290 return "";
1293 OptionHelp format;
1295 size_t longest = 0;
1297 String result;
1299 if (!g.empty())
1301 result += toLocalString(" " + g + " options:\n");
1304 for (const auto& o : group->second.options)
1306 if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end())
1308 continue;
1311 auto s = format_option(o);
1312 longest = std::max(longest, stringLength(s));
1313 format.push_back(std::make_pair(s, String()));
1316 longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));
1318 //widest allowed description
1319 auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
1321 auto fiter = format.begin();
1322 for (const auto& o : group->second.options)
1324 if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end())
1326 continue;
1329 auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
1331 result += fiter->first;
1332 if (stringLength(fiter->first) > longest)
1334 result += '\n';
1335 result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
1337 else
1339 result += toLocalString(std::string(longest + OPTION_DESC_GAP -
1340 stringLength(fiter->first),
1341 ' '));
1343 result += d;
1344 result += '\n';
1346 ++fiter;
1349 return result;
1352 std::string
1353 Options::help(const std::vector<std::string>& groups) const
1355 String result = m_help_string + "\nUsage:\n " +
1356 toLocalString(m_program) + " [OPTION...]";
1358 if (m_positional.size() > 0) {
1359 result += " positional parameters";
1362 result += "\n\n";
1364 for (std::size_t i = 0; i < groups.size(); ++i)
1366 String const& group_help = help_one_group(groups[i]);
1367 if (group_help.empty()) continue;
1368 result += group_help;
1369 if (i < groups.size() - 1)
1371 result += '\n';
1375 return toUTF8String(result);
1378 const std::vector<std::string>
1379 Options::groups() const
1381 std::vector<std::string> g;
1383 std::transform(
1384 m_help.begin(),
1385 m_help.end(),
1386 std::back_inserter(g),
1387 [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
1389 return pair.first;
1393 return g;
1396 const HelpGroupDetails&
1397 Options::group_help(const std::string& group) const
1399 return m_help.at(group);
1404 #if defined(__GNU__)
1405 #pragma GCC diagnostic pop
1406 #endif
1408 #endif //CXX_OPTS_HPP