mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1422 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1422 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						||
 | 
						||
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
 | 
						||
      {
 | 
						||
        if (m_implicit && text.empty())
 | 
						||
        {
 | 
						||
          parse_value(m_implicit_value, *m_store);
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          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_next_positional(m_positional.end())
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    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;
 | 
						||
 | 
						||
    std::string m_program;
 | 
						||
    String m_help_string;
 | 
						||
 | 
						||
    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, "");
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
      throw missing_argument_exception(name);
 | 
						||
    }
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {
 | 
						||
    if (argv[current + 1][0] == '-' && value->value().has_implicit())
 | 
						||
    {
 | 
						||
      parse_option(value, name, "");
 | 
						||
    }
 | 
						||
    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, "");
 | 
						||
            }
 | 
						||
            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)
 | 
						||
    {
 | 
						||
      consume_positional(argv[current]);
 | 
						||
      ++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;
 | 
						||
}
 | 
						||
 | 
						||
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 += " positional parameters";
 | 
						||
  }
 | 
						||
 | 
						||
  result += "\n\n";
 | 
						||
 | 
						||
  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';
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  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
 |