Chris@16: // Copyright Vladimir Prus 2004. Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt Chris@16: // or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_VALUE_SEMANTIC_HPP_VP_2004_02_24 Chris@16: #define BOOST_VALUE_SEMANTIC_HPP_VP_2004_02_24 Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace program_options { Chris@16: Chris@16: /** Class which specifies how the option's value is to be parsed Chris@16: and converted into C++ types. Chris@16: */ Chris@16: class BOOST_PROGRAM_OPTIONS_DECL value_semantic { Chris@16: public: Chris@16: /** Returns the name of the option. The name is only meaningful Chris@16: for automatic help message. Chris@16: */ Chris@16: virtual std::string name() const = 0; Chris@16: Chris@16: /** The minimum number of tokens for this option that Chris@16: should be present on the command line. */ Chris@16: virtual unsigned min_tokens() const = 0; Chris@16: Chris@16: /** The maximum number of tokens for this option that Chris@16: should be present on the command line. */ Chris@16: virtual unsigned max_tokens() const = 0; Chris@16: Chris@16: /** Returns true if values from different sources should be composed. Chris@16: Otherwise, value from the first source is used and values from Chris@16: other sources are discarded. Chris@16: */ Chris@16: virtual bool is_composing() const = 0; Chris@16: Chris@16: /** Returns true if value must be given. Non-optional value Chris@16: Chris@16: */ Chris@16: virtual bool is_required() const = 0; Chris@16: Chris@16: /** Parses a group of tokens that specify a value of option. Chris@16: Stores the result in 'value_store', using whatever representation Chris@16: is desired. May be be called several times if value of the same Chris@16: option is specified more than once. Chris@16: */ Chris@16: virtual void parse(boost::any& value_store, Chris@16: const std::vector& new_tokens, Chris@16: bool utf8) const Chris@16: = 0; Chris@16: Chris@16: /** Called to assign default value to 'value_store'. Returns Chris@16: true if default value is assigned, and false if no default Chris@16: value exists. */ Chris@16: virtual bool apply_default(boost::any& value_store) const = 0; Chris@16: Chris@16: /** Called when final value of an option is determined. Chris@16: */ Chris@16: virtual void notify(const boost::any& value_store) const = 0; Chris@16: Chris@16: virtual ~value_semantic() {} Chris@16: }; Chris@16: Chris@16: /** Helper class which perform necessary character conversions in the Chris@16: 'parse' method and forwards the data further. Chris@16: */ Chris@16: template Chris@16: class value_semantic_codecvt_helper { Chris@16: // Nothing here. Specializations to follow. Chris@16: }; Chris@16: Chris@16: /** Helper conversion class for values that accept ascii Chris@16: strings as input. Chris@16: Overrides the 'parse' method and defines new 'xparse' Chris@16: method taking std::string. Depending on whether input Chris@16: to parse is ascii or UTF8, will pass it to xparse unmodified, Chris@16: or with UTF8->ascii conversion. Chris@16: */ Chris@16: template<> Chris@16: class BOOST_PROGRAM_OPTIONS_DECL Chris@16: value_semantic_codecvt_helper : public value_semantic { Chris@16: private: // base overrides Chris@16: void parse(boost::any& value_store, Chris@16: const std::vector& new_tokens, Chris@16: bool utf8) const; Chris@16: protected: // interface for derived classes. Chris@16: virtual void xparse(boost::any& value_store, Chris@16: const std::vector& new_tokens) Chris@16: const = 0; Chris@16: }; Chris@16: Chris@16: /** Helper conversion class for values that accept ascii Chris@16: strings as input. Chris@16: Overrides the 'parse' method and defines new 'xparse' Chris@16: method taking std::wstring. Depending on whether input Chris@16: to parse is ascii or UTF8, will recode input to Unicode, or Chris@16: pass it unmodified. Chris@16: */ Chris@16: template<> Chris@16: class BOOST_PROGRAM_OPTIONS_DECL Chris@16: value_semantic_codecvt_helper : public value_semantic { Chris@16: private: // base overrides Chris@16: void parse(boost::any& value_store, Chris@16: const std::vector& new_tokens, Chris@16: bool utf8) const; Chris@16: protected: // interface for derived classes. Chris@16: #if !defined(BOOST_NO_STD_WSTRING) Chris@16: virtual void xparse(boost::any& value_store, Chris@16: const std::vector& new_tokens) Chris@16: const = 0; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: /** Class which specifies a simple handling of a value: the value will Chris@16: have string type and only one token is allowed. */ Chris@16: class BOOST_PROGRAM_OPTIONS_DECL Chris@16: untyped_value : public value_semantic_codecvt_helper { Chris@16: public: Chris@16: untyped_value(bool zero_tokens = false) Chris@16: : m_zero_tokens(zero_tokens) Chris@16: {} Chris@16: Chris@16: std::string name() const; Chris@16: Chris@16: unsigned min_tokens() const; Chris@16: unsigned max_tokens() const; Chris@16: Chris@16: bool is_composing() const { return false; } Chris@16: Chris@16: bool is_required() const { return false; } Chris@16: Chris@16: /** If 'value_store' is already initialized, or new_tokens Chris@16: has more than one elements, throws. Otherwise, assigns Chris@16: the first string from 'new_tokens' to 'value_store', without Chris@16: any modifications. Chris@16: */ Chris@16: void xparse(boost::any& value_store, Chris@16: const std::vector& new_tokens) const; Chris@16: Chris@16: /** Does nothing. */ Chris@16: bool apply_default(boost::any&) const { return false; } Chris@16: Chris@16: /** Does nothing. */ Chris@16: void notify(const boost::any&) const {} Chris@16: private: Chris@16: bool m_zero_tokens; Chris@16: }; Chris@16: Chris@16: /** Base class for all option that have a fixed type, and are Chris@16: willing to announce this type to the outside world. Chris@16: Any 'value_semantics' for which you want to find out the Chris@16: type can be dynamic_cast-ed to typed_value_base. If conversion Chris@16: succeeds, the 'type' method can be called. Chris@16: */ Chris@16: class typed_value_base Chris@16: { Chris@16: public: Chris@16: // Returns the type of the value described by this Chris@16: // object. Chris@16: virtual const std::type_info& value_type() const = 0; Chris@16: // Not really needed, since deletion from this Chris@16: // class is silly, but just in case. Chris@16: virtual ~typed_value_base() {} Chris@16: }; Chris@16: Chris@16: Chris@16: /** Class which handles value of a specific type. */ Chris@16: template Chris@16: class typed_value : public value_semantic_codecvt_helper, Chris@16: public typed_value_base Chris@16: { Chris@16: public: Chris@16: /** Ctor. The 'store_to' parameter tells where to store Chris@16: the value when it's known. The parameter can be NULL. */ Chris@16: typed_value(T* store_to) Chris@16: : m_store_to(store_to), m_composing(false), Chris@16: m_multitoken(false), m_zero_tokens(false), Chris@16: m_required(false) Chris@16: {} Chris@16: Chris@16: /** Specifies default value, which will be used Chris@16: if none is explicitly specified. The type 'T' should Chris@16: provide operator<< for ostream. Chris@16: */ Chris@16: typed_value* default_value(const T& v) Chris@16: { Chris@16: m_default_value = boost::any(v); Chris@16: m_default_value_as_text = boost::lexical_cast(v); Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies default value, which will be used Chris@16: if none is explicitly specified. Unlike the above overload, Chris@16: the type 'T' need not provide operator<< for ostream, Chris@16: but textual representation of default value must be provided Chris@16: by the user. Chris@16: */ Chris@16: typed_value* default_value(const T& v, const std::string& textual) Chris@16: { Chris@16: m_default_value = boost::any(v); Chris@16: m_default_value_as_text = textual; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies an implicit value, which will be used Chris@16: if the option is given, but without an adjacent value. Chris@16: Using this implies that an explicit value is optional, but if Chris@16: given, must be strictly adjacent to the option, i.e.: '-ovalue' Chris@16: or '--option=value'. Giving '-o' or '--option' will cause the Chris@16: implicit value to be applied. Chris@16: */ Chris@16: typed_value* implicit_value(const T &v) Chris@16: { Chris@16: m_implicit_value = boost::any(v); Chris@16: m_implicit_value_as_text = Chris@16: boost::lexical_cast(v); Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies the name used to to the value in help message. */ Chris@16: typed_value* value_name(const std::string& name) Chris@16: { Chris@16: m_value_name = name; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies an implicit value, which will be used Chris@16: if the option is given, but without an adjacent value. Chris@16: Using this implies that an explicit value is optional, but if Chris@16: given, must be strictly adjacent to the option, i.e.: '-ovalue' Chris@16: or '--option=value'. Giving '-o' or '--option' will cause the Chris@16: implicit value to be applied. Chris@16: Unlike the above overload, the type 'T' need not provide Chris@16: operator<< for ostream, but textual representation of default Chris@16: value must be provided by the user. Chris@16: */ Chris@16: typed_value* implicit_value(const T &v, const std::string& textual) Chris@16: { Chris@16: m_implicit_value = boost::any(v); Chris@16: m_implicit_value_as_text = textual; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies a function to be called when the final value Chris@16: is determined. */ Chris@16: typed_value* notifier(function1 f) Chris@16: { Chris@16: m_notifier = f; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies that the value is composing. See the 'is_composing' Chris@16: method for explanation. Chris@16: */ Chris@16: typed_value* composing() Chris@16: { Chris@16: m_composing = true; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies that the value can span multiple tokens. Chris@16: */ Chris@16: typed_value* multitoken() Chris@16: { Chris@16: m_multitoken = true; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies that no tokens may be provided as the value of Chris@16: this option, which means that only presense of the option Chris@16: is significant. For such option to be useful, either the Chris@16: 'validate' function should be specialized, or the Chris@16: 'implicit_value' method should be also used. In most Chris@16: cases, you can use the 'bool_switch' function instead of Chris@16: using this method. */ Chris@16: typed_value* zero_tokens() Chris@16: { Chris@16: m_zero_tokens = true; Chris@16: return this; Chris@16: } Chris@16: Chris@16: /** Specifies that the value must occur. */ Chris@16: typed_value* required() Chris@16: { Chris@16: m_required = true; Chris@16: return this; Chris@16: } Chris@16: Chris@16: public: // value semantic overrides Chris@16: Chris@16: std::string name() const; Chris@16: Chris@16: bool is_composing() const { return m_composing; } Chris@16: Chris@16: unsigned min_tokens() const Chris@16: { Chris@16: if (m_zero_tokens || !m_implicit_value.empty()) { Chris@16: return 0; Chris@16: } else { Chris@16: return 1; Chris@16: } Chris@16: } Chris@16: Chris@16: unsigned max_tokens() const { Chris@16: if (m_multitoken) { Chris@16: return 32000; Chris@16: } else if (m_zero_tokens) { Chris@16: return 0; Chris@16: } else { Chris@16: return 1; Chris@16: } Chris@16: } Chris@16: Chris@16: bool is_required() const { return m_required; } Chris@16: Chris@16: /** Creates an instance of the 'validator' class and calls Chris@16: its operator() to perform the actual conversion. */ Chris@16: void xparse(boost::any& value_store, Chris@16: const std::vector< std::basic_string >& new_tokens) Chris@16: const; Chris@16: Chris@16: /** If default value was specified via previous call to Chris@16: 'default_value', stores that value into 'value_store'. Chris@16: Returns true if default value was stored. Chris@16: */ Chris@16: virtual bool apply_default(boost::any& value_store) const Chris@16: { Chris@16: if (m_default_value.empty()) { Chris@16: return false; Chris@16: } else { Chris@16: value_store = m_default_value; Chris@16: return true; Chris@16: } Chris@16: } Chris@16: Chris@16: /** If an address of variable to store value was specified Chris@16: when creating *this, stores the value there. Otherwise, Chris@16: does nothing. */ Chris@16: void notify(const boost::any& value_store) const; Chris@16: Chris@16: public: // typed_value_base overrides Chris@16: Chris@16: const std::type_info& value_type() const Chris@16: { Chris@16: return typeid(T); Chris@16: } Chris@16: Chris@16: Chris@16: private: Chris@16: T* m_store_to; Chris@16: Chris@16: // Default value is stored as boost::any and not Chris@16: // as boost::optional to avoid unnecessary instantiations. Chris@16: std::string m_value_name; Chris@16: boost::any m_default_value; Chris@16: std::string m_default_value_as_text; Chris@16: boost::any m_implicit_value; Chris@16: std::string m_implicit_value_as_text; Chris@16: bool m_composing, m_implicit, m_multitoken, m_zero_tokens, m_required; Chris@16: boost::function1 m_notifier; Chris@16: }; Chris@16: Chris@16: Chris@16: /** Creates a typed_value instance. This function is the primary Chris@16: method to create value_semantic instance for a specific type, which Chris@16: can later be passed to 'option_description' constructor. Chris@16: The second overload is used when it's additionally desired to store the Chris@16: value of option into program variable. Chris@16: */ Chris@16: template Chris@16: typed_value* Chris@16: value(); Chris@16: Chris@16: /** @overload Chris@16: */ Chris@16: template Chris@16: typed_value* Chris@16: value(T* v); Chris@16: Chris@16: /** Creates a typed_value instance. This function is the primary Chris@16: method to create value_semantic instance for a specific type, which Chris@16: can later be passed to 'option_description' constructor. Chris@16: */ Chris@16: template Chris@16: typed_value* Chris@16: wvalue(); Chris@16: Chris@16: /** @overload Chris@16: */ Chris@16: template Chris@16: typed_value* Chris@16: wvalue(T* v); Chris@16: Chris@16: /** Works the same way as the 'value' function, but the created Chris@16: value_semantic won't accept any explicit value. So, if the option Chris@16: is present on the command line, the value will be 'true'. Chris@16: */ Chris@16: BOOST_PROGRAM_OPTIONS_DECL typed_value* Chris@16: bool_switch(); Chris@16: Chris@16: /** @overload Chris@16: */ Chris@16: BOOST_PROGRAM_OPTIONS_DECL typed_value* Chris@16: bool_switch(bool* v); Chris@16: Chris@16: }} Chris@16: Chris@16: #include "boost/program_options/detail/value_semantic.hpp" Chris@16: Chris@16: #endif Chris@16: