1 //
2 // Copyright (c) 2004-2017 Benjamin Kaufmann
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 // IN THE SOFTWARE.
21 //
22 //
23 // NOTE: ProgramOptions is inspired by Boost.Program_options
24 //       see: www.boost.org/libs/program_options
25 //
26 #ifndef PROGRAM_OPTIONS_VALUE_H_INCLUDED
27 #define PROGRAM_OPTIONS_VALUE_H_INCLUDED
28 #ifdef _MSC_VER
29 #pragma warning (disable : 4786)
30 #pragma warning (disable : 4503)
31 #endif
32 #include <string>
33 #include <typeinfo>
34 #include <cstddef>
35 #if defined(_MSC_VER) && _MSC_VER <= 1200
36 namespace std { using ::size_t; }
37 #endif
38 
39 namespace Potassco { namespace ProgramOptions { namespace detail {
40 template <class T>
41 struct Owned {
~OwnedOwned42 	~Owned() { delete obj; }
43 	T* obj;
44 };
45 } // namespace detail
46 enum DescriptionLevel {
47 	desc_level_default = 0, /**< Always shown in description */
48 	desc_level_e1 = 1,
49 	desc_level_e2 = 2,
50 	desc_level_e3 = 3,
51 	desc_level_all = 4,
52 	desc_level_hidden = 5 /**< Never shown in description */
53 };
54 
55 //! Manages the value of an option and defines how it is parsed from a string.
56 /*!
57  * The library maintains a 1:1-relationship between options and their values.
58  * That is, an option has exactly one value and a value has exactly one
59  * state w.r.t its option.
60  */
61 class Value {
62 public:
63 	//! Possible (tentative) states of an option value.
64 	enum State {
65 		value_unassigned = 0, /**< no value assigned */
66 		value_defaulted = 1, /**< a default value is assigned */
67 		value_fixed = 2  /**< a parsed value is assigned */
68 	};
69 	//! Possible value descriptions.
70 	enum DescType {
71 		desc_name = 1
72 		, desc_default = 2
73 		, desc_implicit = 4
74 	};
75 	virtual ~Value();
76 
77 	//! Returns the current state of this value.
state()78 	State state() const { return static_cast<State>(state_); }
79 
80 	/*!
81 	 * Sets the (initial) state of this value to s.
82 	 */
state(Value::State s)83 	Value* state(Value::State s) {
84 		state(true, s);
85 		return this;
86 	}
87 
88 	//! Returns the name of this value.
89 	/*!
90 	 * \note The default name is "<arg>" unless isFlag() is true in which
91 	 *       case the default is "".
92 	 */
93 	const char* arg()          const;
arg(const char * n)94 	Value*      arg(const char* n) { return desc(desc_name, n); }
95 
96 	//! Sets an alias name for the corresponding option.
alias(char c)97 	Value* alias(char c) { optAlias_ = c; return this; }
alias()98 	char   alias() const { return optAlias_; }
99 	//! Sets a description level for the corresponding option.
100 	/*!
101 	 * Description levels can be used to suppress
102 	 * certain options when generating option descriptions.
103 	 */
level(DescriptionLevel lev)104 	Value* level(DescriptionLevel lev) {
105 		unsigned x = (lev * level_shift);
106 		flags_ = static_cast<byte_t>(x | (flags_&(level_shift-1)));
107 		return this;
108 	}
109 	//! Returns the description level of the corresponding option.
level()110 	DescriptionLevel level() const { return DescriptionLevel(flags_ / level_shift); }
111 
112 	//! Returns true if this is the value of an negatable option.
113 	/*!
114 	 * If an option '--option' is negatable, passing '--no-option'
115 	 * on the command-line will set the value of '--option' to 'no'.
116 	 */
isNegatable()117 	bool isNegatable() const { return hasProperty(property_negatable); }
negatable()118 	Value* negatable() { setProperty(property_negatable); return this; }
119 
120 
121 	//! Returns true if value can be implicitly created from an empty string.
122 	/*!
123 	 * \note the implicit value comes into play if the corresponding
124 	 *       option is present but without an adjacent value.
125 	 *
126 	 * \note an explicit value for an implicit value is only used if
127 	 *       it is unambiguously given. E.g. on the command-line one has
128 	 *       to use '--option=value' or '-ovalue' but *not* '--option value'
129 	 *       or '-o value'.
130 	 */
isImplicit()131 	bool   isImplicit() const { return hasProperty(property_implicit); }
132 
133 	//! Returns true if this is the value of an option flag.
134 	/*!
135 	 * Similar to isImplicit but with the difference that
136 	 * no value is accepted on the command-line.
137 	 *
138 	 * Used for options like '--help' or '--version'.
139 	 */
isFlag()140 	bool isFlag() const { return hasProperty(property_flag); }
141 
142 	/*!
143 	 * Marks the value as flag.
144 	 * \see bool Value::isFlag() const
145 	 */
flag()146 	Value* flag() { setProperty(property_flag); return this; }
147 
148 
149 	//! Returns true if the value of this option can be composed from multiple source.
isComposing()150 	bool isComposing() const { return hasProperty(property_composing); }
151 	/*!
152 	 * Marks the value as composing.
153 	 * \see Value::isComposing()
154 	 */
composing()155 	Value* composing() { setProperty(property_composing); return this; }
156 
157 	/*!
158 	 * Sets a default value for this value.
159 	 */
defaultsTo(const char * v)160 	Value* defaultsTo(const char* v) { return desc(desc_default, v); }
161 	//! Returns the default value of this or 0 none exists
defaultsTo()162 	const char* defaultsTo()  const { return desc(desc_default); }
163 	/*!
164 	 * Sets an implicit value, which will be used
165 	 * if option is given without an adjacent value,
166 	 * e.g. '--option' instead of '--option value'
167 	 * \see bool Value::isImplicit() const
168 	 */
implicit(const char * str)169 	Value* implicit(const char* str) { return desc(desc_implicit, str); }
170 	//! Returns the implicit value of this or 0 if isImplicit() == false.
171 	const char* implicit() const;
172 
173 	//! Parses the given string and updates the value's state.
174 	/*!
175 	 * \param name  The name of the option associated with this value.
176 	 * \param value The value to parse.
177 	 * \param st    The state to which the value should transition if parsing is successful.
178 	 *
179 	 * \return
180 	 * - true if the given string contains a valid value
181 	 * - false otherwise
182 	 *
183 	 * \post if true is returned, state() is st
184 	 */
185 	bool parse(const std::string& name, const std::string& value, State st = value_fixed);
186 protected:
187 	typedef unsigned char byte_t;
188 	enum Property {
189 		property_implicit = 1 // implicit value?
190 		, property_flag = 3 // implicit and type bool?
191 		, property_composing = 4 // multiple values allowed?
192 		, property_negatable = 8 // negatable form allowed?
193 		, property_location = 16 // fixed storage location?
194 		, not_a_property = 32
195 	};
196 	Value(byte_t flagSet, State initial = value_unassigned);
setProperty(Property f)197 	void setProperty(Property f) { flags_ |= byte_t(f); }
clearProperty(Property f)198 	void clearProperty(Property f) { flags_ &= ~byte_t(f); }
hasProperty(Property f)199 	bool hasProperty(Property f)const { return (flags_ & byte_t(f)) == f; }
state(bool b,State s)200 	bool state(bool b, State s) { if (b) { state_ = static_cast<byte_t>(s); } return b; }
201 	virtual bool doParse(const std::string& name, const std::string& value) = 0;
202 	const char* desc(DescType t) const;
203 	Value*      desc(DescType t, const char* d);
204 private:
205 	enum { desc_pack = 8, level_shift = not_a_property, levels = 255/level_shift };
206 	byte_t state_;       // state: one of State
207 	byte_t flags_;       // flag set holding properties
208 	byte_t descFlag_;    // either desc_pack or one of DescType
209 	byte_t optAlias_;    // alias name of option
210 	union ValueDesc {    // optional value descriptions either
211 		const char*  value;// a single value or
212 		const char** pack; // a pointer to a full pack
213 	}      desc_;
214 };
215 } // namespace ProgramOptions
216 } // namespace Potassco
217 #endif
218