Home | History | Annotate | Download | only in decpp
      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).
     69 	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.
     81 	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.
     93 	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>
    106 	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>
    126 inline void getTypeDefault (ValueType* dst)
    127 {
    128 	*dst = ValueType();
    129 }
    130 
    131 template<> void getTypeDefault<bool> (bool* dst);
    132 
    133 template<typename T>	inline bool isBoolean		(void) { return false;	}
    134 template<>				inline bool isBoolean<bool>	(void) { return true;	}
    135 
    136 //! Is argument boolean-only value?
    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 {
    158 	static void destroy (void* value) { delete (Value*)value; }
    159 };
    160 
    161 class TypedFieldMap
    162 {
    163 public:
    164 						TypedFieldMap			(void);
    165 						~TypedFieldMap			(void);
    166 
    167 	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 
    194 		Entry (void) : value(DE_NULL), destructor(0) {}
    195 		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>
    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>
    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>
    230 inline bool TypedFieldMap::contains (void) const
    231 {
    232 	return contains(&typeid(Name));
    233 }
    234 
    235 template<typename Name>
    236 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 
    284 		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>
    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>
    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>
    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>
    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>
    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>
    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:
    397 								CommandLine		(void) {}
    398 								~CommandLine	(void) {}
    399 
    400 	void						clear			(void);
    401 
    402 	const TypedFieldMap&		getOptions		(void) const	{ return m_options;	}
    403 	const vector<string>&		getArgs			(void) const	{ return m_args;	}
    404 
    405 	template<typename Option>
    406 	bool						hasOption		(void) const	{ return m_options.contains<Option>();	}
    407 
    408 	template<typename Option>
    409 	const typename TypedFieldTraits<Option>::ValueType&
    410 								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