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