1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468 |
- /*
-
- Copyright (c) 2014, 2015, 2016 Jarryd Beck
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
- */
-
- #ifndef CXX_OPTS_HPP
- #define CXX_OPTS_HPP
-
- #if defined(__GNUC__)
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
- #endif
-
- #include <cstring>
- #include <exception>
- #include <iostream>
- #include <map>
- #include <memory>
- #include <regex>
- #include <sstream>
- #include <string>
- #include <unordered_set>
- #include <vector>
-
- //when we ask cxxopts to use Unicode, help strings are processed using ICU,
- //which results in the correct lengths being computed for strings when they
- //are formatted for the help output
- //it is necessary to make sure that <unicode/unistr.h> can be found by the
- //compiler, and that icu-uc is linked in to the binary.
-
- #ifdef CXXOPTS_USE_UNICODE
- #include <unicode/unistr.h>
-
- namespace cxxopts
- {
- typedef icu::UnicodeString String;
-
- inline
- String
- toLocalString(std::string s)
- {
- return icu::UnicodeString::fromUTF8(s);
- }
-
- class UnicodeStringIterator : public
- std::iterator<std::forward_iterator_tag, int32_t>
- {
- public:
-
- UnicodeStringIterator(const icu::UnicodeString* s, int32_t pos)
- : s(s)
- , i(pos)
- {
- }
-
- value_type
- operator*() const
- {
- return s->char32At(i);
- }
-
- bool
- operator==(const UnicodeStringIterator& rhs) const
- {
- return s == rhs.s && i == rhs.i;
- }
-
- bool
- operator!=(const UnicodeStringIterator& rhs) const
- {
- return !(*this == rhs);
- }
-
- UnicodeStringIterator&
- operator++()
- {
- ++i;
- return *this;
- }
-
- UnicodeStringIterator
- operator+(int32_t v)
- {
- return UnicodeStringIterator(s, i + v);
- }
-
- private:
- const icu::UnicodeString* s;
- int32_t i;
- };
-
- inline
- String&
- stringAppend(String&s, String a)
- {
- return s.append(std::move(a));
- }
-
- inline
- String&
- stringAppend(String& s, int n, UChar32 c)
- {
- for (int i = 0; i != n; ++i)
- {
- s.append(c);
- }
-
- return s;
- }
-
- template <typename Iterator>
- String&
- stringAppend(String& s, Iterator begin, Iterator end)
- {
- while (begin != end)
- {
- s.append(*begin);
- ++begin;
- }
-
- return s;
- }
-
- inline
- size_t
- stringLength(const String& s)
- {
- return s.length();
- }
-
- inline
- std::string
- toUTF8String(const String& s)
- {
- std::string result;
- s.toUTF8String(result);
-
- return result;
- }
-
- inline
- bool
- empty(const String& s)
- {
- return s.isEmpty();
- }
- }
-
- namespace std
- {
- cxxopts::UnicodeStringIterator
- begin(const icu::UnicodeString& s)
- {
- return cxxopts::UnicodeStringIterator(&s, 0);
- }
-
- cxxopts::UnicodeStringIterator
- end(const icu::UnicodeString& s)
- {
- return cxxopts::UnicodeStringIterator(&s, s.length());
- }
- }
-
- //ifdef CXXOPTS_USE_UNICODE
- #else
-
- namespace cxxopts
- {
- typedef std::string String;
-
- template <typename T>
- T
- toLocalString(T&& t)
- {
- return t;
- }
-
- inline
- size_t
- stringLength(const String& s)
- {
- return s.length();
- }
-
- inline
- String&
- stringAppend(String&s, String a)
- {
- return s.append(std::move(a));
- }
-
- inline
- String&
- stringAppend(String& s, size_t n, char c)
- {
- return s.append(n, c);
- }
-
- template <typename Iterator>
- String&
- stringAppend(String& s, Iterator begin, Iterator end)
- {
- return s.append(begin, end);
- }
-
- template <typename T>
- std::string
- toUTF8String(T&& t)
- {
- return std::forward<T>(t);
- }
-
- inline
- bool
- empty(const std::string& s)
- {
- return s.empty();
- }
- }
-
- //ifdef CXXOPTS_USE_UNICODE
- #endif
-
- namespace cxxopts
- {
- class Value : public std::enable_shared_from_this<Value>
- {
- public:
-
- virtual void
- parse(const std::string& text) const = 0;
-
- virtual void
- parse() const = 0;
-
- virtual bool
- has_arg() const = 0;
-
- virtual bool
- has_default() const = 0;
-
- virtual bool
- is_container() const = 0;
-
- virtual bool
- has_implicit() const = 0;
-
- virtual std::string
- get_default_value() const = 0;
-
- virtual std::string
- get_implicit_value() const = 0;
-
- virtual std::shared_ptr<Value>
- default_value(const std::string& value) = 0;
-
- virtual std::shared_ptr<Value>
- implicit_value(const std::string& value) = 0;
- };
-
- class OptionException : public std::exception
- {
- public:
- OptionException(const std::string& message)
- : m_message(message)
- {
- }
-
- virtual const char*
- what() const noexcept
- {
- return m_message.c_str();
- }
-
- private:
- std::string m_message;
- };
-
- class OptionSpecException : public OptionException
- {
- public:
-
- OptionSpecException(const std::string& message)
- : OptionException(message)
- {
- }
- };
-
- class OptionParseException : public OptionException
- {
- public:
- OptionParseException(const std::string& message)
- : OptionException(message)
- {
- }
- };
-
- class option_exists_error : public OptionSpecException
- {
- public:
- option_exists_error(const std::string& option)
- : OptionSpecException(u8"Option ‘" + option + u8"’ already exists")
- {
- }
- };
-
- class invalid_option_format_error : public OptionSpecException
- {
- public:
- invalid_option_format_error(const std::string& format)
- : OptionSpecException(u8"Invalid option format ‘" + format + u8"’")
- {
- }
- };
-
- class option_not_exists_exception : public OptionParseException
- {
- public:
- option_not_exists_exception(const std::string& option)
- : OptionParseException(u8"Option ‘" + option + u8"’ does not exist")
- {
- }
- };
-
- class missing_argument_exception : public OptionParseException
- {
- public:
- missing_argument_exception(const std::string& option)
- : OptionParseException(u8"Option ‘" + option + u8"’ is missing an argument")
- {
- }
- };
-
- class option_requires_argument_exception : public OptionParseException
- {
- public:
- option_requires_argument_exception(const std::string& option)
- : OptionParseException(u8"Option ‘" + option + u8"’ requires an argument")
- {
- }
- };
-
- class option_not_has_argument_exception : public OptionParseException
- {
- public:
- option_not_has_argument_exception
- (
- const std::string& option,
- const std::string& arg
- )
- : OptionParseException(
- u8"Option ‘" + option + u8"’ does not take an argument, but argument‘"
- + arg + "’ given")
- {
- }
- };
-
- class option_not_present_exception : public OptionParseException
- {
- public:
- option_not_present_exception(const std::string& option)
- : OptionParseException(u8"Option ‘" + option + u8"’ not present")
- {
- }
- };
-
- class argument_incorrect_type : public OptionParseException
- {
- public:
- argument_incorrect_type
- (
- const std::string& arg
- )
- : OptionParseException(
- u8"Argument ‘" + arg + u8"’ failed to parse"
- )
- {
- }
- };
-
- namespace values
- {
- template <typename T>
- void
- parse_value(const std::string& text, T& value)
- {
- std::istringstream is(text);
- if (!(is >> value))
- {
- throw argument_incorrect_type(text);
- }
-
- if (is.rdbuf()->in_avail() != 0)
- {
- throw argument_incorrect_type(text);
- }
- }
-
- inline
- void
- parse_value(const std::string& /*text*/, bool& value)
- {
- //TODO recognise on, off, yes, no, enable, disable
- //so that we can write --long=yes explicitly
- value = true;
- }
-
- inline
- void
- parse_value(const std::string& text, std::string& value)
- {
- value = text;
- }
-
- template <typename T>
- void
- parse_value(const std::string& text, std::vector<T>& value)
- {
- T v;
- parse_value(text, v);
- value.push_back(v);
- }
-
- template <typename T>
- struct value_has_arg
- {
- static constexpr bool value = true;
- };
-
- template <>
- struct value_has_arg<bool>
- {
- static constexpr bool value = false;
- };
-
- template <typename T>
- struct type_is_container
- {
- static constexpr bool value = false;
- };
-
- template <typename T>
- struct type_is_container<std::vector<T>>
- {
- static constexpr bool value = true;
- };
-
- template <typename T>
- class standard_value : public Value
- {
- public:
- standard_value()
- : m_result(std::make_shared<T>())
- , m_store(m_result.get())
- {
- }
-
- standard_value(T* t)
- : m_store(t)
- {
- }
-
- void
- parse(const std::string& text) const
- {
- parse_value(text, *m_store);
- }
-
- bool
- is_container() const
- {
- return type_is_container<T>::value;
- }
-
- void
- parse() const
- {
- parse_value(m_default_value, *m_store);
- }
-
- bool
- has_arg() const
- {
- return value_has_arg<T>::value;
- }
-
- bool
- has_default() const
- {
- return m_default;
- }
-
- bool
- has_implicit() const
- {
- return m_implicit;
- }
-
- virtual std::shared_ptr<Value>
- default_value(const std::string& value){
- m_default = true;
- m_default_value = value;
- return shared_from_this();
- }
-
- virtual std::shared_ptr<Value>
- implicit_value(const std::string& value){
- m_implicit = true;
- m_implicit_value = value;
- return shared_from_this();
- }
-
- std::string
- get_default_value() const
- {
- return m_default_value;
- }
-
- std::string
- get_implicit_value() const
- {
- return m_implicit_value;
- }
-
- const T&
- get() const
- {
- if (m_store == nullptr)
- {
- return *m_result;
- }
- else
- {
- return *m_store;
- }
- }
-
- protected:
- std::shared_ptr<T> m_result;
- T* m_store;
- bool m_default = false;
- std::string m_default_value;
- bool m_implicit = false;
- std::string m_implicit_value;
- };
- }
-
- template <typename T>
- std::shared_ptr<Value>
- value()
- {
- return std::make_shared<values::standard_value<T>>();
- }
-
- template <typename T>
- std::shared_ptr<Value>
- value(T& t)
- {
- return std::make_shared<values::standard_value<T>>(&t);
- }
-
- class OptionAdder;
-
- class OptionDetails
- {
- public:
- OptionDetails
- (
- const String& description,
- std::shared_ptr<const Value> value
- )
- : m_desc(description)
- , m_value(value)
- , m_count(0)
- {
- }
-
- const String&
- description() const
- {
- return m_desc;
- }
-
- bool
- has_arg() const
- {
- return m_value->has_arg();
- }
-
- void
- parse(const std::string& text)
- {
- m_value->parse(text);
- ++m_count;
- }
-
- void
- parse_default()
- {
- m_value->parse();
- }
-
- int
- count() const
- {
- return m_count;
- }
-
- const Value& value() const {
- return *m_value;
- }
-
- template <typename T>
- const T&
- as() const
- {
- #ifdef CXXOPTS_NO_RTTI
- return static_cast<const values::standard_value<T>&>(*m_value).get();
- #else
- return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
- #endif
- }
-
- private:
- String m_desc;
- std::shared_ptr<const Value> m_value;
- int m_count;
- };
-
- struct HelpOptionDetails
- {
- std::string s;
- std::string l;
- String desc;
- bool has_arg;
- bool has_default;
- std::string default_value;
- bool has_implicit;
- std::string implicit_value;
- std::string arg_help;
- bool is_container;
- };
-
- struct HelpGroupDetails
- {
- std::string name;
- std::string description;
- std::vector<HelpOptionDetails> options;
- };
-
- class Options
- {
- public:
-
- Options(std::string program, std::string help_string = "")
- : m_program(std::move(program))
- , m_help_string(toLocalString(std::move(help_string)))
- , m_positional_help("positional parameters")
- , m_next_positional(m_positional.end())
- {
- }
-
- inline
- Options&
- positional_help(const std::string& help_text)
- {
- m_positional_help = std::move(help_text);
- return *this;
- }
-
- inline
- void
- parse(int& argc, char**& argv);
-
- inline
- OptionAdder
- add_options(std::string group = "");
-
- inline
- void
- add_option
- (
- const std::string& group,
- const std::string& s,
- const std::string& l,
- std::string desc,
- std::shared_ptr<const Value> value,
- std::string arg_help
- );
-
- int
- count(const std::string& o) const
- {
- auto iter = m_options.find(o);
- if (iter == m_options.end())
- {
- return 0;
- }
-
- return iter->second->count();
- }
-
- const OptionDetails&
- operator[](const std::string& option) const
- {
- auto iter = m_options.find(option);
-
- if (iter == m_options.end())
- {
- throw option_not_present_exception(option);
- }
-
- return *iter->second;
- }
-
- //parse positional arguments into the given option
- inline
- void
- parse_positional(std::string option);
-
- inline
- void
- parse_positional(std::vector<std::string> options);
-
- inline
- std::string
- help(const std::vector<std::string>& groups = {""}) const;
-
- inline
- const std::vector<std::string>
- groups() const;
-
- inline
- const HelpGroupDetails&
- group_help(const std::string& group) const;
-
- private:
-
- inline
- void
- add_one_option
- (
- const std::string& option,
- std::shared_ptr<OptionDetails> details
- );
-
- inline
- bool
- consume_positional(std::string a);
-
- inline
- void
- add_to_option(const std::string& option, const std::string& arg);
-
- inline
- void
- parse_option
- (
- std::shared_ptr<OptionDetails> value,
- const std::string& name,
- const std::string& arg = ""
- );
-
- inline
- void
- checked_parse_arg
- (
- int argc,
- char* argv[],
- int& current,
- std::shared_ptr<OptionDetails> value,
- const std::string& name
- );
-
- inline
- String
- help_one_group(const std::string& group) const;
-
- inline
- void
- generate_group_help(String& result, const std::vector<std::string>& groups) const;
-
- inline
- void
- generate_all_groups_help(String& result) const;
-
- std::string m_program;
- String m_help_string;
- std::string m_positional_help;
-
- std::map<std::string, std::shared_ptr<OptionDetails>> m_options;
- std::vector<std::string> m_positional;
- std::vector<std::string>::iterator m_next_positional;
- std::unordered_set<std::string> m_positional_set;
-
- //mapping from groups to help options
- std::map<std::string, HelpGroupDetails> m_help;
- };
-
- class OptionAdder
- {
- public:
-
- OptionAdder(Options& options, std::string group)
- : m_options(options), m_group(std::move(group))
- {
- }
-
- inline
- OptionAdder&
- operator()
- (
- const std::string& opts,
- const std::string& desc,
- std::shared_ptr<const Value> value
- = ::cxxopts::value<bool>(),
- std::string arg_help = ""
- );
-
- private:
- Options& m_options;
- std::string m_group;
- };
-
- }
-
- namespace cxxopts
- {
-
- namespace
- {
-
- constexpr int OPTION_LONGEST = 30;
- constexpr int OPTION_DESC_GAP = 2;
-
- std::basic_regex<char> option_matcher
- ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
-
- std::basic_regex<char> option_specifier
- ("(([[:alnum:]]),)?([[:alnum:]][-_[:alnum:]]+)");
-
- String
- format_option
- (
- const HelpOptionDetails& o
- )
- {
- auto& s = o.s;
- auto& l = o.l;
-
- String result = " ";
-
- if (s.size() > 0)
- {
- result += "-" + toLocalString(s) + ",";
- }
- else
- {
- result += " ";
- }
-
- if (l.size() > 0)
- {
- result += " --" + toLocalString(l);
- }
-
- if (o.has_arg)
- {
- auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
-
- if (o.has_implicit)
- {
- result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
- }
- else
- {
- result += " " + arg;
- }
- }
-
- return result;
- }
-
- String
- format_description
- (
- const HelpOptionDetails& o,
- size_t start,
- size_t width
- )
- {
- auto desc = o.desc;
-
- if (o.has_default)
- {
- desc += toLocalString(" (default: " + o.default_value + ")");
- }
-
- String result;
-
- auto current = std::begin(desc);
- auto startLine = current;
- auto lastSpace = current;
-
- auto size = size_t{};
-
- while (current != std::end(desc))
- {
- if (*current == ' ')
- {
- lastSpace = current;
- }
-
- if (size > width)
- {
- if (lastSpace == startLine)
- {
- stringAppend(result, startLine, current + 1);
- stringAppend(result, "\n");
- stringAppend(result, start, ' ');
- startLine = current + 1;
- lastSpace = startLine;
- }
- else
- {
- stringAppend(result, startLine, lastSpace);
- stringAppend(result, "\n");
- stringAppend(result, start, ' ');
- startLine = lastSpace + 1;
- }
- size = 0;
- }
- else
- {
- ++size;
- }
-
- ++current;
- }
-
- //append whatever is left
- stringAppend(result, startLine, current);
-
- return result;
- }
- }
-
- OptionAdder
- Options::add_options(std::string group)
- {
- return OptionAdder(*this, std::move(group));
- }
-
- OptionAdder&
- OptionAdder::operator()
- (
- const std::string& opts,
- const std::string& desc,
- std::shared_ptr<const Value> value,
- std::string arg_help
- )
- {
- std::match_results<const char*> result;
- std::regex_match(opts.c_str(), result, option_specifier);
-
- if (result.empty())
- {
- throw invalid_option_format_error(opts);
- }
-
- const auto& s = result[2];
- const auto& l = result[3];
-
- m_options.add_option(m_group, s.str(), l.str(), desc, value,
- std::move(arg_help));
-
- return *this;
- }
-
- void
- Options::parse_option
- (
- std::shared_ptr<OptionDetails> value,
- const std::string& /*name*/,
- const std::string& arg
- )
- {
- value->parse(arg);
- }
-
- void
- Options::checked_parse_arg
- (
- int argc,
- char* argv[],
- int& current,
- std::shared_ptr<OptionDetails> value,
- const std::string& name
- )
- {
- if (current + 1 >= argc)
- {
- if (value->value().has_implicit())
- {
- parse_option(value, name, value->value().get_implicit_value());
- }
- else
- {
- throw missing_argument_exception(name);
- }
- }
- else
- {
- if (argv[current + 1][0] == '-' && value->value().has_implicit())
- {
- parse_option(value, name, value->value().get_implicit_value());
- }
- else
- {
- parse_option(value, name, argv[current + 1]);
- ++current;
- }
- }
- }
-
- void
- Options::add_to_option(const std::string& option, const std::string& arg)
- {
- auto iter = m_options.find(option);
-
- if (iter == m_options.end())
- {
- throw option_not_exists_exception(option);
- }
-
- parse_option(iter->second, option, arg);
- }
-
- bool
- Options::consume_positional(std::string a)
- {
- while (m_next_positional != m_positional.end())
- {
- auto iter = m_options.find(*m_next_positional);
- if (iter != m_options.end())
- {
- if (!iter->second->value().is_container())
- {
- if (iter->second->count() == 0)
- {
- add_to_option(*m_next_positional, a);
- ++m_next_positional;
- return true;
- }
- else
- {
- ++m_next_positional;
- continue;
- }
- }
- else
- {
- add_to_option(*m_next_positional, a);
- return true;
- }
- }
- ++m_next_positional;
- }
-
- return false;
- }
-
- void
- Options::parse_positional(std::string option)
- {
- parse_positional(std::vector<std::string>{option});
- }
-
- void
- Options::parse_positional(std::vector<std::string> options)
- {
- m_positional = std::move(options);
- m_next_positional = m_positional.begin();
-
- m_positional_set.insert(m_positional.begin(), m_positional.end());
- }
-
- void
- Options::parse(int& argc, char**& argv)
- {
- int current = 1;
-
- int nextKeep = 1;
-
- bool consume_remaining = false;
-
- while (current != argc)
- {
- if (strcmp(argv[current], "--") == 0)
- {
- consume_remaining = true;
- ++current;
- break;
- }
-
- std::match_results<const char*> result;
- std::regex_match(argv[current], result, option_matcher);
-
- if (result.empty())
- {
- //not a flag
-
- //if true is returned here then it was consumed, otherwise it is
- //ignored
- if (consume_positional(argv[current]))
- {
- }
- else
- {
- argv[nextKeep] = argv[current];
- ++nextKeep;
- }
- //if we return from here then it was parsed successfully, so continue
- }
- else
- {
- //short or long option?
- if (result[4].length() != 0)
- {
- const std::string& s = result[4];
-
- for (std::size_t i = 0; i != s.size(); ++i)
- {
- std::string name(1, s[i]);
- auto iter = m_options.find(name);
-
- if (iter == m_options.end())
- {
- throw option_not_exists_exception(name);
- }
-
- auto value = iter->second;
-
- //if no argument then just add it
- if (!value->has_arg())
- {
- parse_option(value, name);
- }
- else
- {
- //it must be the last argument
- if (i + 1 == s.size())
- {
- checked_parse_arg(argc, argv, current, value, name);
- }
- else if (value->value().has_implicit())
- {
- parse_option(value, name, value->value().get_implicit_value());
- }
- else
- {
- //error
- throw option_requires_argument_exception(name);
- }
- }
- }
- }
- else if (result[1].length() != 0)
- {
- const std::string& name = result[1];
-
- auto iter = m_options.find(name);
-
- if (iter == m_options.end())
- {
- throw option_not_exists_exception(name);
- }
-
- auto opt = iter->second;
-
- //equals provided for long option?
- if (result[3].length() != 0)
- {
- //parse the option given
-
- //but if it doesn't take an argument, this is an error
- if (!opt->has_arg())
- {
- throw option_not_has_argument_exception(name, result[3]);
- }
-
- parse_option(opt, name, result[3]);
- }
- else
- {
- if (opt->has_arg())
- {
- //parse the next argument
- checked_parse_arg(argc, argv, current, opt, name);
- }
- else
- {
- //parse with empty argument
- parse_option(opt, name);
- }
- }
- }
-
- }
-
- ++current;
- }
-
- for (auto& opt : m_options)
- {
- auto& detail = opt.second;
- auto& value = detail->value();
-
- if(!detail->count() && value.has_default()){
- detail->parse_default();
- }
- }
-
- if (consume_remaining)
- {
- while (current < argc)
- {
- if (!consume_positional(argv[current])) {
- break;
- }
- ++current;
- }
-
- //adjust argv for any that couldn't be swallowed
- while (current != argc) {
- argv[nextKeep] = argv[current];
- ++nextKeep;
- ++current;
- }
- }
-
- argc = nextKeep;
-
- }
-
- void
- Options::add_option
- (
- const std::string& group,
- const std::string& s,
- const std::string& l,
- std::string desc,
- std::shared_ptr<const Value> value,
- std::string arg_help
- )
- {
- auto stringDesc = toLocalString(std::move(desc));
- auto option = std::make_shared<OptionDetails>(stringDesc, value);
-
- if (s.size() > 0)
- {
- add_one_option(s, option);
- }
-
- if (l.size() > 0)
- {
- add_one_option(l, option);
- }
-
- //add the help details
- auto& options = m_help[group];
-
- options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
- value->has_arg(),
- value->has_default(), value->get_default_value(),
- value->has_implicit(), value->get_implicit_value(),
- std::move(arg_help),
- value->is_container()});
- }
-
- void
- Options::add_one_option
- (
- const std::string& option,
- std::shared_ptr<OptionDetails> details
- )
- {
- auto in = m_options.emplace(option, details);
-
- if (!in.second)
- {
- throw option_exists_error(option);
- }
- }
-
- String
- Options::help_one_group(const std::string& g) const
- {
- typedef std::vector<std::pair<String, String>> OptionHelp;
-
- auto group = m_help.find(g);
- if (group == m_help.end())
- {
- return "";
- }
-
- OptionHelp format;
-
- size_t longest = 0;
-
- String result;
-
- if (!g.empty())
- {
- result += toLocalString(" " + g + " options:\n");
- }
-
- for (const auto& o : group->second.options)
- {
- if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end())
- {
- continue;
- }
-
- auto s = format_option(o);
- longest = std::max(longest, stringLength(s));
- format.push_back(std::make_pair(s, String()));
- }
-
- longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));
-
- //widest allowed description
- auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
-
- auto fiter = format.begin();
- for (const auto& o : group->second.options)
- {
- if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end())
- {
- continue;
- }
-
- auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
-
- result += fiter->first;
- if (stringLength(fiter->first) > longest)
- {
- result += '\n';
- result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
- }
- else
- {
- result += toLocalString(std::string(longest + OPTION_DESC_GAP -
- stringLength(fiter->first),
- ' '));
- }
- result += d;
- result += '\n';
-
- ++fiter;
- }
-
- return result;
- }
-
- void
- Options::generate_group_help(String& result, const std::vector<std::string>& groups) const
- {
- for (std::size_t i = 0; i < groups.size(); ++i)
- {
- String const& group_help = help_one_group(groups[i]);
- if (empty(group_help)) continue;
- result += group_help;
- if (i < groups.size() - 1)
- {
- result += '\n';
- }
- }
- }
-
- void
- Options::generate_all_groups_help(String& result) const
- {
- std::vector<std::string> groups;
- groups.reserve(m_help.size());
-
- for (auto& group : m_help)
- {
- groups.push_back(group.first);
- }
-
- generate_group_help(result, groups);
- }
-
- std::string
- Options::help(const std::vector<std::string>& groups) const
- {
- String result = m_help_string + "\nUsage:\n " +
- toLocalString(m_program) + " [OPTION...]";
-
- if (m_positional.size() > 0) {
- result += " " + toLocalString(m_positional_help);
- }
-
- result += "\n\n";
-
- if (groups.size() == 0)
- {
- generate_all_groups_help(result);
- }
- else
- {
- generate_group_help(result, groups);
- }
-
- return toUTF8String(result);
- }
-
- const std::vector<std::string>
- Options::groups() const
- {
- std::vector<std::string> g;
-
- std::transform(
- m_help.begin(),
- m_help.end(),
- std::back_inserter(g),
- [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
- {
- return pair.first;
- }
- );
-
- return g;
- }
-
- const HelpGroupDetails&
- Options::group_help(const std::string& group) const
- {
- return m_help.at(group);
- }
-
- }
-
- #if defined(__GNU__)
- #pragma GCC diagnostic pop
- #endif
-
- #endif //CXX_OPTS_HPP
|