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 35namespace de 36{ 37namespace cmdline 38{ 39 40//! Default parsing function 41template<typename ValueType> 42void parseType (const char* src, ValueType* dst); 43 44template<typename T> 45struct NamedValue 46{ 47 const char* name; 48 T value; 49}; 50 51template<typename OptName> 52struct 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 default should be T() 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 118template<class Option> 119struct OptTraits 120{ 121 typedef typename Option::ValueType ValueType; 122}; 123 124//! Default value lookup 125template<typename ValueType> 126inline void getTypeDefault (ValueType* dst) 127{ 128 *dst = ValueType(); 129} 130 131template<> void getTypeDefault<bool> (bool* dst); 132 133template<typename T> inline bool isBoolean (void) { return false; } 134template<> inline bool isBoolean<bool> (void) { return true; } 135 136//! Is argument boolean-only value? 137template<class Option> inline bool isBooleanOpt (void) { return isBoolean<typename OptTraits<Option>::ValueType>(); } 138 139namespace detail 140{ 141 142using std::string; 143using std::vector; 144using std::map; 145 146// TypedFieldMap implementation 147 148template<class Name> 149struct TypedFieldTraits 150{ 151 // Generic implementation for cmdline. 152 typedef typename OptTraits<Name>::ValueType ValueType; 153}; 154 155template<class Value> 156struct TypedFieldValueTraits 157{ 158 static void destroy (void* value) { delete (Value*)value; } 159}; 160 161class TypedFieldMap 162{ 163public: 164 TypedFieldMap (void); 165 ~TypedFieldMap (void); 166 167 bool empty (void) const { return m_fields.empty(); } 168 void clear (void) { m_fields.clear(); } 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 183private: 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 207template<typename Name> 208inline void TypedFieldMap::set (typename TypedFieldTraits<Name>::ValueType* value) 209{ 210 set(&typeid(Name), Entry(value, &TypedFieldValueTraits<typename TypedFieldTraits<Name>::ValueType>::destroy)); 211} 212 213template<typename Name> 214void 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 229template<typename Name> 230inline bool TypedFieldMap::contains (void) const 231{ 232 return contains(&typeid(Name)); 233} 234 235template<typename Name> 236inline const typename TypedFieldTraits<Name>::ValueType& TypedFieldMap::get (void) const 237{ 238 return *static_cast<typename TypedFieldTraits<Name>::ValueType*>(get(&typeid(Name)).value); 239} 240 241class CommandLine; 242 243typedef void (*GenericParseFunc) (const char* src, void* dst); 244 245class Parser 246{ 247public: 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 258private: 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 (*GetDefaultFunc) (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 GetDefaultFunc getDefault; 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 , getDefault (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 307template<class OptType> 308inline 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. 315const void* findNamedValueMatch (const char* src, const void* namedValues, const void* namedValuesEnd, size_t stride); 316 317template<typename OptType> 318void 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 342template<typename OptType> 343void dispatchGetDefault (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 358template<typename OptType> 359const 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 365template<typename OptType> 366void 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 372template<class OptType> 373void 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 opt.getDefault = dispatchGetDefault<OptType>; 388 389 addOption(opt); 390} 391 392class CommandLine 393{ 394public: 395 CommandLine (void) {} 396 ~CommandLine (void) {} 397 398 void clear (void); 399 400 const TypedFieldMap& getOptions (void) const { return m_options; } 401 const vector<string>& getArgs (void) const { return m_args; } 402 403 template<typename Option> 404 const typename TypedFieldTraits<Option>::ValueType& 405 getOption (void) const { return m_options.get<Option>(); } 406 407private: 408 TypedFieldMap m_options; 409 vector<string> m_args; 410 411 friend class Parser; 412}; 413 414} // detail 415 416using detail::Parser; 417using detail::CommandLine; 418 419void selfTest (void); 420 421} // cmdline 422} // de 423 424#define DE_DECLARE_COMMAND_LINE_OPT(NAME, TYPE) struct NAME { typedef TYPE ValueType; } 425 426#endif // _DECOMMANDLINE_HPP 427