Changeset 2087 for code/trunk/src/core/CommandLine.h
- Timestamp:
- Nov 1, 2008, 7:04:09 PM (17 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
-
code/trunk/src/core/CommandLine.h
r1764 r2087 35 35 #include "util/Debug.h" 36 36 #include "util/Exception.h" 37 #include "util/MultiType.h" 37 38 38 39 #define SetCommandLineArgument(name, defaultValue) \ 39 BaseCommandLineArgument& CmdArgumentDummyBoolVar##name \40 CommandLineArgument& CmdArgumentDummyBoolVar##name \ 40 41 = orxonox::CommandLine::addArgument(#name, defaultValue) 41 42 #define SetCommandLineSwitch(name) \ 42 BaseCommandLineArgument& CmdArgumentDummyBoolVar##name \43 CommandLineArgument& CmdArgumentDummyBoolVar##name \ 43 44 = orxonox::CommandLine::addArgument(#name, false) 44 45 … … 48 49 /** 49 50 @brief 50 Template struct which creates a distinct type for every integer constant. 51 @note 52 This allows to select a different function depending on a boolean value 53 when creating a new CommandLineArgument. 54 From 'Modern C++ Design' (Alexandrescu 2001). 51 Container class for a command line argument of any type supported by MultiType. 52 53 Whenever you want to have an option specified by a command line switch, 54 you need to first define it with SetCommandLineArgument(name, defaultValue). 55 It is then added to a map and possibly changed when the command line is being parsed. 56 If the option was not given, you can detect this by asking hasDefaultValue(). 57 58 There is a possibility to define a short cut so you can write "-p 20" instead of "--port 20". 59 Note the difference between "-" and "--"! 60 Also, there is no restriction to the number of strings you add after --name. 61 So "--startVector (2, 4, 5)" is perfectly legal. 62 63 Retrieving an argument is possible with the getCommandLineArgument function of the 64 CommandLine class. It is a Singleton, but the public interface is static. 55 65 */ 56 template <int v> 57 struct Int2Type 58 { 59 enum { value = v }; 60 }; 61 62 /** 63 @brief 64 Base class for CommandLineArguments. 65 */ 66 class _CoreExport BaseCommandLineArgument 66 class _CoreExport CommandLineArgument 67 67 { 68 68 friend class CommandLine; … … 78 78 const std::string& getShortcut() const { return shortcut_; } 79 79 //! Sets the shortcut for the argument 80 BaseCommandLineArgument& setShortcut(const std::string& shortcut)80 CommandLineArgument& shortcut(const std::string& shortcut) 81 81 { this->shortcut_ = shortcut; return *this; } 82 82 … … 84 84 const std::string& getInformation() const { return this->usageInformation_; } 85 85 //! Sets the option information when displaying orxonox usage. 86 BaseCommandLineArgument& setInformation(const std::string& usage)86 CommandLineArgument& information(const std::string& usage) 87 87 { this->usageInformation_ = usage; return *this; } 88 88 89 protected: 90 BaseCommandLineArgument(const std::string& name) 89 //! Returns the actual value of the argument. Can be equal to default value. 90 MultiType getValue() const { return value_; } 91 //! Returns the given default value as type T. 92 MultiType getDefaultValue() const { return defaultValue_; } 93 94 private: 95 //! Constructor initialises both value_ and defaultValue_ with defaultValue. 96 CommandLineArgument(const std::string& name, const MultiType& defaultValue) 91 97 : bHasDefaultValue_(true) 92 98 , name_(name) 99 , value_(defaultValue) 100 , defaultValue_(defaultValue) 93 101 { } 94 102 95 103 //! Undefined copy constructor 96 BaseCommandLineArgument(const BaseCommandLineArgument& instance);97 virtual ~BaseCommandLineArgument() { }104 CommandLineArgument(const CommandLineArgument& instance); 105 ~CommandLineArgument() { } 98 106 99 107 //! Parses the value string of a command line argument. 100 v irtual void parse(const std::string& value) = 0;108 void parse(const std::string& value); 101 109 102 110 //! Tells whether the value has been changed by the command line. … … 107 115 std::string shortcut_; //!< Shortcut of the argument. @see getShortcut(). 108 116 std::string usageInformation_; //!< Tells about the usage of this parameter 117 118 MultiType value_; //!< The actual value 119 MultiType defaultValue_; //!< Default value. Should not be changed. 109 120 }; 110 111 112 /**113 @brief114 Container class for a command line argument of type T.115 116 Whenever you want to have an option specified by a command line switch,117 you need to first define it with SetCommandLineArgument(name, defaultValue).118 It is then added to a map and possibly changed when the command line is being parsed.119 If the option was not given, you can detect this by asking hasDefaultValue().120 121 There is a possibility to define a short cut so you can write "-p 20" instead of "--port 20".122 Note the difference between "-" and "--"!123 Also, there is no restriction to the number of strings you add after --name.124 So "--startVector (2, 4, 5)" is perfectly legal.125 126 Retrieving an argument is possible with the getCommandLineArgument function of the127 CommandLine class. It is a Singleton, but the public interface is static.128 */129 template <class T>130 class CommandLineArgument : public BaseCommandLineArgument131 {132 // Only let CommandLine change the value.133 friend class CommandLine;134 135 public:136 //! Returns the actual value of the argument. Can be equal to default value.137 T getValue() const { return value_; }138 //! Returns the given default value as type T.139 T getDefaultValue() const { return defaultValue_; }140 141 private:142 //! Constructor initialises both value_ and defaultValue_ with defaultValue.143 CommandLineArgument(const std::string& name, const T& defaultValue)144 : BaseCommandLineArgument(name)145 , value_(defaultValue)146 , defaultValue_(defaultValue)147 { }148 149 virtual void parse(const std::string& value);150 151 T value_; //!< The actual value152 T defaultValue_; //!< Default value. Should not be changed.153 };154 155 /**156 @brief157 Parses a value string for a command line argument.158 It simply uses convertValue(Output, Input) to do that.159 */160 template <class T>161 void CommandLineArgument<T>::parse(const std::string& value)162 {163 if (convertValue(&this->value_, value))164 {165 this->bHasDefaultValue_ = false;166 }167 else168 {169 ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");170 }171 }172 173 /**174 @brief175 Parses a value string for a command line argument.176 It simply uses convertValue(Output, Input) to do that.177 This is a template specialisation for bool type. That is necessary178 so that you can have simple command line switches.179 */180 template <>181 inline void CommandLineArgument<bool>::parse(const std::string& value)182 {183 if (convertValue(&this->value_, value))184 {185 this->bHasDefaultValue_ = false;186 }187 else if (value == "")188 {189 this->bHasDefaultValue_ = false;190 this->value_ = true;191 }192 else193 {194 ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");195 }196 }197 121 198 122 … … 215 139 static std::string getUsageInformation(); 216 140 217 template <class T> 218 static const CommandLineArgument<T>* getArgument(const std::string& name); 141 static const CommandLineArgument* getArgument(const std::string& name); 219 142 //! Writes the argument value in the given parameter. 220 143 template <class T> 221 144 static void getValue(const std::string& name, T* value) 222 { *value = getArgument<T>(name)->getValue(); } 145 { *value = (T)(getArgument(name)->getValue()); } 146 static MultiType getValue(const std::string& name) 147 { return getArgument(name)->getValue(); } 223 148 template <class T> 224 static BaseCommandLineArgument& addArgument(const std::string& name, T defaultValue); 149 static CommandLineArgument& addArgument(const std::string& name, T defaultValue); 150 151 static bool existsArgument(const std::string& name) 152 { 153 std::map<std::string, CommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name); 154 return !(it == _getInstance().cmdLineArgs_.end()); 155 } 156 225 157 226 158 private: … … 237 169 void checkShortcut(const std::string& shortcut, const std::string& value); 238 170 239 template <class T>240 BaseCommandLineArgument* createArg(const std::string& name, T defaultValue, Int2Type<0> isString);241 template <class T>242 BaseCommandLineArgument* createArg(const std::string& name, T defaultValue, Int2Type<1> isString);243 244 171 /** 245 Tells whether we parse the first expression. The CommmandLineArguments are added before main().172 Tells whether we parsed for the first time. The CommmandLineArguments are added before main(). 246 173 So when we call parse() the first time, we need to create a map with all shortcuts since these 247 174 get added after addCommandLineArgument(). … … 250 177 251 178 //! Holds all pointers to the arguments and serves as a search map by name. 252 std::map<std::string, BaseCommandLineArgument*> cmdLineArgs_;179 std::map<std::string, CommandLineArgument*> cmdLineArgs_; 253 180 //! Search map by chortcut for the arguments. 254 std::map<std::string, BaseCommandLineArgument*> cmdLineArgsShortcut_;181 std::map<std::string, CommandLineArgument*> cmdLineArgsShortcut_; 255 182 }; 256 183 257 258 /** 259 @brief 260 Retrieves a CommandLineArgument. 261 The method throws an exception if 'name' was not found or the value could not be converted. 262 @note 263 You shold of course not call this method before the command line has been parsed. 264 */ 265 template <class T> 266 const CommandLineArgument<T>* CommandLine::getArgument(const std::string& name) 267 { 268 std::map<std::string, BaseCommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name); 269 if (it == _getInstance().cmdLineArgs_.end()) 270 { 271 ThrowException(Argument, "Could find command line argument '" + name + "'."); 272 } 273 else 274 { 275 CommandLineArgument<T>* arg = dynamic_cast<CommandLineArgument<T>* >(it->second); 276 if (arg == 0) 277 { 278 ThrowException(Argument, "Could not convert command line argument value to requested type. " \ 279 "You should use exactly the same type as predefined."); 280 } 281 else 282 { 283 return arg; 284 } 285 } 184 template <> 185 inline void CommandLine::getValue<std::string>(const std::string& name, std::string* value) 186 { 187 *value = (std::string)(getArgument(name)->getValue().getString()); 286 188 } 287 189 … … 294 196 @param defaultValue 295 197 Default value that is used when argument was not given. 296 @note297 In order to store char* strings as std::string too, there's298 little bit of template programming involved:299 StaticConversions::exists determines whether T converts to std::string.300 Int2Type<int> is then used to call the right function. One returns301 a CommandLineArgument<T> and the other CommandLineArgument<std::string>.302 198 */ 303 199 template <class T> 304 BaseCommandLineArgument& CommandLine::addArgument(const std::string& name, T defaultValue) 305 { 306 std::map<std::string, BaseCommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name); 307 OrxAssert(it == _getInstance().cmdLineArgs_.end(), 200 CommandLineArgument& CommandLine::addArgument(const std::string& name, T defaultValue) 201 { 202 OrxAssert(!_getInstance().existsArgument(name), 308 203 "Cannot add a command line argument with name '" + name + "' twice."); 309 204 310 return *(_getInstance().cmdLineArgs_[name] = 311 _getInstance().createArg(name, defaultValue, Int2Type<StaticConversion<T, std::string>::exists>())); 312 } 313 314 /** 315 Returns a new CommandLineArgument<T>. 316 */ 317 template <class T> 318 BaseCommandLineArgument* CommandLine::createArg(const std::string& name, T defaultValue, Int2Type<0> isPrime) 319 { 320 return new CommandLineArgument<T>(name, defaultValue); 321 } 322 323 /** 324 Returns a new CommandLineArgument<std::string>. 325 */ 326 template <class T> 327 BaseCommandLineArgument* CommandLine::createArg(const std::string& name, T defaultValue, Int2Type<1> isPrime) 328 { 329 return new CommandLineArgument<std::string>(name, defaultValue); 205 return *(_getInstance().cmdLineArgs_[name] = new CommandLineArgument(name, defaultValue)); 330 206 } 331 207 }
Note: See TracChangeset
for help on using the changeset viewer.