1 #ifndef _DECOMMANDLINE_HPP
2 #define _DECOMMANDLINE_HPP
3 /*-------------------------------------------------------------------------
4  * drawElements C++ Base Library
5  * -----------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Command line parser.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "deDefs.hpp"
27 
28 #include <map>
29 #include <string>
30 #include <vector>
31 #include <ostream>
32 #include <typeinfo>
33 #include <stdexcept>
34 
35 namespace de
36 {
37 namespace cmdline
38 {
39 
40 //! Default parsing function
41 template<typename ValueType>
42 void parseType (const char* src, ValueType* dst);
43 
44 template<typename T>
45 struct NamedValue
46 {
47 	const char*	name;
48 	T			value;
49 };
50 
51 template<typename OptName>
52 struct Option
53 {
54 	typedef typename OptName::ValueType ValueType;
55 	typedef void (*ParseFunc) (const char* src, ValueType* dst);
56 
57 	// \note All assumed to point to static memory.
58 	const char*						shortName;
59 	const char*						longName;
60 	const char*						description;
61 	const char*						defaultValue;		//!< Default value (parsed from string), or null if should not be set
62 
63 	// \note Either parse or namedValues must be null.
64 	ParseFunc						parse;				//!< Custom parsing function or null.
65 	const NamedValue<ValueType>*	namedValues;		//!< Named values or null.
66 	const NamedValue<ValueType>*	namedValuesEnd;		//!< Named value list end.
67 
68 	//! Construct generic option (string, int, boolean).
Optionde::cmdline::Option69 	Option (const char* shortName_, const char* longName_, const char* description_, const char* defaultValue_ = DE_NULL)
70 		: shortName		(shortName_)
71 		, longName		(longName_)
72 		, description	(description_)
73 		, defaultValue	(defaultValue_)
74 		, parse			(parseType<ValueType>)
75 		, namedValues	(DE_NULL)
76 		, namedValuesEnd(0)
77 	{
78 	}
79 
80 	//! Option with custom parsing function.
Optionde::cmdline::Option81 	Option (const char* shortName_, const char* longName_, const char* description_, ParseFunc parse_, const char* defaultValue_ = DE_NULL)
82 		: shortName		(shortName_)
83 		, longName		(longName_)
84 		, description	(description_)
85 		, defaultValue	(defaultValue_)
86 		, parse			(parse_)
87 		, namedValues	(DE_NULL)
88 		, namedValuesEnd(DE_NULL)
89 	{
90 	}
91 
92 	//! Option that uses named values.
Optionde::cmdline::Option93 	Option (const char* shortName_, const char* longName_, const char* description_, const NamedValue<ValueType>* namedValues_, const NamedValue<ValueType>* namedValuesEnd_, const char* defaultValue_ = DE_NULL)
94 		: shortName		(shortName_)
95 		, longName		(longName_)
96 		, description	(description_)
97 		, defaultValue	(defaultValue_)
98 		, parse			((ParseFunc)DE_NULL)
99 		, namedValues	(namedValues_)
100 		, namedValuesEnd(namedValuesEnd_)
101 	{
102 	}
103 
104 	//! Option that uses named values.
105 	template<size_t NumNamedValues>
Optionde::cmdline::Option106 	Option (const char* shortName_, const char* longName_, const char* description_, const NamedValue<ValueType> (&namedValues_)[NumNamedValues], const char* defaultValue_ = DE_NULL)
107 		: shortName		(shortName_)
108 		, longName		(longName_)
109 		, description	(description_)
110 		, defaultValue	(defaultValue_)
111 		, parse			((ParseFunc)DE_NULL)
112 		, namedValues	(DE_ARRAY_BEGIN(namedValues_))
113 		, namedValuesEnd(DE_ARRAY_END(namedValues_))
114 	{
115 	}
116 };
117 
118 template<class Option>
119 struct OptTraits
120 {
121 	typedef typename Option::ValueType ValueType;
122 };
123 
124 //! Default value lookup
125 template<typename ValueType>
getTypeDefault(ValueType * dst)126 inline void getTypeDefault (ValueType* dst)
127 {
128 	*dst = ValueType();
129 }
130 
131 template<> void getTypeDefault<bool> (bool* dst);
132 
isBoolean(void)133 template<typename T>	inline bool isBoolean		(void) { return false;	}
isBoolean(void)134 template<>				inline bool isBoolean<bool>	(void) { return true;	}
135 
136 //! Is argument boolean-only value?
isBooleanOpt(void)137 template<class Option>	inline bool isBooleanOpt	(void) { return isBoolean<typename OptTraits<Option>::ValueType>(); }
138 
139 namespace detail
140 {
141 
142 using std::string;
143 using std::vector;
144 using std::map;
145 
146 // TypedFieldMap implementation
147 
148 template<class Name>
149 struct TypedFieldTraits
150 {
151 	// Generic implementation for cmdline.
152 	typedef typename OptTraits<Name>::ValueType	ValueType;
153 };
154 
155 template<class Value>
156 struct TypedFieldValueTraits
157 {
destroyde::cmdline::detail::TypedFieldValueTraits158 	static void destroy (void* value) { delete (Value*)value; }
159 };
160 
161 class TypedFieldMap
162 {
163 public:
164 						TypedFieldMap			(void);
165 						~TypedFieldMap			(void);
166 
empty(void) const167 	bool				empty					(void) const	{ return m_fields.empty();	}
168 	void				clear					(void);
169 
170 	template<typename Name>
171 	void				set						(typename TypedFieldTraits<Name>::ValueType* value);
172 
173 	template<typename Name>
174 	void				set						(const typename TypedFieldTraits<Name>::ValueType& value);
175 
176 	template<typename Name>
177 	bool				contains				(void) const;
178 
179 	template<typename Name>
180 	const typename TypedFieldTraits<Name>::ValueType&
181 						get						(void) const;
182 
183 private:
184 						TypedFieldMap			(const TypedFieldMap&);
185 	TypedFieldMap&		operator=				(const TypedFieldMap&);
186 
187 	typedef void (*DestroyFunc) (void*);
188 
189 	struct Entry
190 	{
191 		void*			value;
192 		DestroyFunc		destructor;
193 
Entryde::cmdline::detail::TypedFieldMap::Entry194 		Entry (void) : value(DE_NULL), destructor(0) {}
Entryde::cmdline::detail::TypedFieldMap::Entry195 		Entry (void* value_, DestroyFunc destructor_) : value(value_), destructor(destructor_) {}
196 	};
197 
198 	typedef std::map<const std::type_info*, Entry> Map;
199 
200 	bool				contains				(const std::type_info* key) const;
201 	const Entry&		get						(const std::type_info* key) const;
202 	void				set						(const std::type_info* key, const Entry& value);
203 
204 	Map					m_fields;
205 };
206 
207 template<typename Name>
set(typename TypedFieldTraits<Name>::ValueType * value)208 inline void TypedFieldMap::set (typename TypedFieldTraits<Name>::ValueType* value)
209 {
210 	set(&typeid(Name), Entry(value, &TypedFieldValueTraits<typename TypedFieldTraits<Name>::ValueType>::destroy));
211 }
212 
213 template<typename Name>
set(const typename TypedFieldTraits<Name>::ValueType & value)214 void TypedFieldMap::set (const typename TypedFieldTraits<Name>::ValueType& value)
215 {
216 	typename TypedFieldTraits<Name>::ValueType* copy = new typename TypedFieldTraits<Name>::ValueType(value);
217 
218 	try
219 	{
220 		set<Name>(copy);
221 	}
222 	catch (...)
223 	{
224 		delete copy;
225 		throw;
226 	}
227 }
228 
229 template<typename Name>
contains(void) const230 inline bool TypedFieldMap::contains (void) const
231 {
232 	return contains(&typeid(Name));
233 }
234 
235 template<typename Name>
get(void) const236 inline const typename TypedFieldTraits<Name>::ValueType& TypedFieldMap::get (void) const
237 {
238 	return *static_cast<typename TypedFieldTraits<Name>::ValueType*>(get(&typeid(Name)).value);
239 }
240 
241 class CommandLine;
242 
243 typedef void (*GenericParseFunc) (const char* src, void* dst);
244 
245 class Parser
246 {
247 public:
248 					Parser				(void);
249 					~Parser				(void);
250 
251 	template<class OptType>
252 	void			addOption			(const Option<OptType>& option);
253 
254 	bool			parse				(int numArgs, const char* const* args, CommandLine* dst, std::ostream& err) const;
255 
256 	void			help				(std::ostream& dst) const;
257 
258 private:
259 					Parser				(const Parser&);
260 	Parser&			operator=			(const Parser&);
261 
262 	struct OptInfo;
263 
264 	typedef void		(*DispatchParseFunc)		(const OptInfo* info, const char* src, TypedFieldMap* dst);
265 	typedef void		(*SetDefaultFunc)			(TypedFieldMap* dst);
266 
267 	struct OptInfo
268 	{
269 		const char*				shortName;
270 		const char*				longName;
271 		const char*				description;
272 		const char*				defaultValue;
273 		bool					isFlag;			//!< Set true for bool typed arguments that do not used named values.
274 
275 		GenericParseFunc		parse;
276 
277 		const void*				namedValues;
278 		const void*				namedValuesEnd;
279 		size_t					namedValueStride;
280 
281 		DispatchParseFunc		dispatchParse;
282 		SetDefaultFunc			setDefault;
283 
OptInfode::cmdline::detail::Parser::OptInfo284 		OptInfo (void)
285 			: shortName			(DE_NULL)
286 			, longName			(DE_NULL)
287 			, description		(DE_NULL)
288 			, defaultValue		(DE_NULL)
289 			, isFlag			(false)
290 			, parse				(DE_NULL)
291 			, namedValues		(DE_NULL)
292 			, namedValuesEnd	(DE_NULL)
293 			, namedValueStride	(0)
294 			, dispatchParse		(DE_NULL)
295 			, setDefault		(DE_NULL)
296 		{}
297 	};
298 
299 	void			addOption			(const OptInfo& option);
300 
301 	template<typename OptName>
302 	static void		dispatchParse		(const OptInfo* info, const char* src, TypedFieldMap* dst);
303 
304 	vector<OptInfo>	m_options;
305 };
306 
307 template<class OptType>
operator <<(Parser & parser,const Option<OptType> & option)308 inline Parser& operator<< (Parser& parser, const Option<OptType>& option)
309 {
310 	parser.addOption(option);
311 	return parser;
312 }
313 
314 //! Find match by name. Throws exception if no match is found.
315 const void* findNamedValueMatch (const char* src, const void* namedValues, const void* namedValuesEnd, size_t stride);
316 
317 template<typename OptType>
dispatchParse(const OptInfo * info,const char * src,TypedFieldMap * dst)318 void Parser::dispatchParse (const OptInfo* info, const char* src, TypedFieldMap* dst)
319 {
320 	typename OptTraits<OptType>::ValueType* value = new typename OptTraits<OptType>::ValueType();
321 	try
322 	{
323 		DE_ASSERT((!!info->parse) != (!!info->namedValues));
324 		if (info->parse)
325 		{
326 			((typename Option<OptType>::ParseFunc)(info->parse))(src, value);
327 		}
328 		else
329 		{
330 			const void* match = findNamedValueMatch(src, info->namedValues, info->namedValuesEnd, info->namedValueStride);
331 			*value = static_cast<const NamedValue<typename OptTraits<OptType>::ValueType>*>(match)->value;
332 		}
333 		dst->set<OptType>(value);
334 	}
335 	catch (...)
336 	{
337 		delete value;
338 		throw;
339 	}
340 }
341 
342 template<typename OptType>
dispatchSetDefault(TypedFieldMap * dst)343 void dispatchSetDefault (TypedFieldMap* dst)
344 {
345 	typename OptTraits<OptType>::ValueType* value = new typename OptTraits<OptType>::ValueType();
346 	try
347 	{
348 		getTypeDefault<typename OptTraits<OptType>::ValueType>(value);
349 		dst->set<OptType>(value);
350 	}
351 	catch (...)
352 	{
353 		delete value;
354 		throw;
355 	}
356 }
357 
358 template<typename OptType>
getNamedValueName(const void * value)359 const char* getNamedValueName (const void* value)
360 {
361 	const NamedValue<typename OptTraits<OptType>::ValueType>* typedVal = static_cast<const NamedValue<typename OptTraits<OptType>::ValueType> >(value);
362 	return typedVal->name;
363 }
364 
365 template<typename OptType>
setFromNamedValue(const void * value,TypedFieldMap * dst)366 void setFromNamedValue (const void* value, TypedFieldMap* dst)
367 {
368 	const NamedValue<typename OptTraits<OptType>::ValueType>* typedVal = static_cast<const NamedValue<typename OptTraits<OptType>::ValueType> >(value);
369 	dst->set<OptType>(typedVal->value);
370 }
371 
372 template<class OptType>
addOption(const Option<OptType> & option)373 void Parser::addOption (const Option<OptType>& option)
374 {
375 	OptInfo opt;
376 
377 	opt.shortName			= option.shortName;
378 	opt.longName			= option.longName;
379 	opt.description			= option.description;
380 	opt.defaultValue		= option.defaultValue;
381 	opt.isFlag				= isBooleanOpt<OptType>() && !option.namedValues;
382 	opt.parse				= (GenericParseFunc)option.parse;
383 	opt.namedValues			= (const void*)option.namedValues;
384 	opt.namedValuesEnd		= (const void*)option.namedValuesEnd;
385 	opt.namedValueStride	= sizeof(*option.namedValues);
386 	opt.dispatchParse		= dispatchParse<OptType>;
387 
388 	if (opt.isFlag)
389 		opt.setDefault		= dispatchSetDefault<OptType>;
390 
391 	addOption(opt);
392 }
393 
394 class CommandLine
395 {
396 public:
CommandLine(void)397 								CommandLine		(void) {}
~CommandLine(void)398 								~CommandLine	(void) {}
399 
400 	void						clear			(void);
401 
getOptions(void) const402 	const TypedFieldMap&		getOptions		(void) const	{ return m_options;	}
getArgs(void) const403 	const vector<string>&		getArgs			(void) const	{ return m_args;	}
404 
405 	template<typename Option>
hasOption(void) const406 	bool						hasOption		(void) const	{ return m_options.contains<Option>();	}
407 
408 	template<typename Option>
409 	const typename TypedFieldTraits<Option>::ValueType&
getOption(void) const410 								getOption		(void) const	{ return m_options.get<Option>();		}
411 
412 private:
413 	TypedFieldMap				m_options;
414 	vector<string>				m_args;
415 
416 	friend class Parser;
417 };
418 
419 } // detail
420 
421 using detail::Parser;
422 using detail::CommandLine;
423 
424 void selfTest (void);
425 
426 } // cmdline
427 } // de
428 
429 #define DE_DECLARE_COMMAND_LINE_OPT(NAME, TYPE) struct NAME { typedef TYPE ValueType; }
430 
431 #endif // _DECOMMANDLINE_HPP
432