cxxopts.hpp
Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (c) 2014 Jarryd Beck
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
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 //when we ask cxxopts to use Unicode, help strings are processed using ICU,
00043 //which results in the correct lengths being computed for strings when they
00044 //are formatted for the help output
00045 //it is necessary to make sure that <unicode/unistr.h> can be found by the
00046 //compiler, and that icu-uc is linked in to the binary.
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 //ifdef CXXOPTS_USE_UNICODE
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 //ifdef CXXOPTS_USE_UNICODE
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& /*text*/, bool& value)
00413     {
00414       //TODO recognise on, off, yes, no, enable, disable
00415       //so that we can write --long=yes explicitly
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     //parse positional arguments into the given option
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     //mapping from groups to help options
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       //append whatever is left
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& /*name*/,
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       //not a flag
01040 
01041       //if true is returned here then it was consumed, otherwise it is
01042       //ignored
01043       if (consume_positional(argv[current]))
01044       {
01045       }
01046       else
01047       {
01048         argv[nextKeep] = argv[current];
01049         ++nextKeep;
01050       }
01051       //if we return from here then it was parsed successfully, so continue
01052     }
01053     else
01054     {
01055       //short or long option?
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           //if no argument then just add it
01073           if (!value->has_arg())
01074           {
01075             parse_option(value, name);
01076           }
01077           else
01078           {
01079             //it must be the last argument
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               //error
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         //equals provided for long option?
01110         if (result[3].length() != 0)
01111         {
01112           //parse the option given
01113 
01114           //but if it doesn't take an argument, this is an error
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             //parse the next argument
01127             checked_parse_arg(argc, argv, current, opt, name);
01128           }
01129           else
01130           {
01131             //parse with empty argument
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   //add the help details
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   //widest allowed description
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


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02