RCFProto

- Main Page
- Classes
- Files

- File List

All Classes Functions Typedefs
CommandLine.hpp
1
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18
19 #ifndef INCLUDE_UTIL_COMMANDLINE_HPP
20 #define INCLUDE_UTIL_COMMANDLINE_HPP
21
22 #include <exception>
23 #include <iostream>
24 #include <map>
25 #include <sstream>
26 #include <stdexcept>
27 #include <vector>
28
29 #ifndef ASSERT
30 #include "Assert.hpp"
31 #define ASSERT(x) UTIL_ASSERT(x, std::runtime_error("Assertion failure (command line parser)"))
32 #define REMEMBER_TO_UNDEFINE_ASSERT
33 #endif
34
35 //*****************************************
36 // Command line parsing utility
37
38 namespace util {
39
40 class I_CommandLineOption {
41 public:
42 virtual ~I_CommandLineOption() {}
43 virtual void notify_begin() = 0;
44 virtual void notify( std::string) = 0;
45 virtual void notify_end() = 0;
46 virtual std::string getName() = 0;
47 virtual std::string getDefaultValue() = 0;
48 virtual std::string getHelpString() = 0;
49 };
50
51 class CommandLine
52 {
53 private:
54 CommandLine()
55 {}
56
57 public:
58 static CommandLine &getSingleton()
59 {
60 static CommandLine commandLine;
61 return commandLine;
62 }
63
64 void parse(int argc, char **argv, bool exitOnHelp = true)
65 {
66 parse(argc, const_cast<const char **>(argv), exitOnHelp);
67 }
68
69 void parse(int argc, const char **argv, bool exitOnHelp = true)
70 {
71 mOptionValues.clear();
72 mArgs.clear();
73 int i=1;
74
75 // If there is no "help" command line option registered, and the only command line option found is "help",
76 // then we print out the helpstrings for all known command line options, and exit.
77 if (argc == 2 && isKey(argv[1]) && toKey(argv[1]) == "help")
78 {
79 if (mOptions.find( "help" ) == mOptions.end())
80 {
81 std::cout << "Available command line switches:\n";
82 for (OptionIterator it = mOptions.begin(); it != mOptions.end(); it++)
83 {
84 if ((*it).second)
85 {
86 I_CommandLineOption *option = (*it).second;
87 std::cout << "-" << option->getName() << "\n";
88 std::cout << "\tDescription: " << option->getHelpString() << "\n";
89 std::cout << "\tDefault: " << option->getDefaultValue() << "\n";
90 }
91 }
92 if (exitOnHelp)
93 {
94 exit(0);
95 }
96 }
97 }
98
99 // Parse the command line
100 while (i < argc)
101 {
102 std::string arg1 = argv[i];
103 i++;
104 std::string arg2 = (i<argc) ? argv[i] : "";
105 i++;
106 if (isKey(arg1))
107 {
108 if (!isKey(arg2) )
109 {
110 mOptionValues[ toKey(arg1) ].push_back( arg2 );
111 }
112 else
113 {
114 mOptionValues[ toKey(arg1) ].push_back( "" );
115 i--;
116 }
117 if (mOptions.find( toKey(arg1) ) == mOptions.end())
118 {
119 // This isn't very useful.
120 //std::cout << "Unrecognized option \"" << arg1 << "\"; type \"-help\" to list all options.\n";
121 }
122 }
123 else
124 {
125 mArgs.push_back( arg1 );
126 i--;
127 }
128 }
129
130 // Notify the registered I_CommandLineOption objects
131 for (OptionIterator iter = mOptions.begin(); iter != mOptions.end(); iter++)
132 {
133 if ((*iter).second)
134 {
135 (*iter).second->notify_begin();
136 }
137 }
138
139 for (OptionValueIterator iter = mOptionValues.begin(); iter != mOptionValues.end(); iter++)
140 {
141 OptionIterator jter = mOptions.find((*iter).first);
142 if (jter != mOptions.end())
143 {
144 for (ValueIterator kter = (*iter).second.begin(); kter != (*iter).second.end(); kter++)
145 {
146 jter->second->notify( *kter );
147 }
148 }
149 }
150
151 for (OptionIterator iter = mOptions.begin(); iter != mOptions.end(); iter++)
152 {
153 if ((*iter).second)
154 {
155 (*iter).second->notify_end();
156 }
157 }
158 }
159
160 void registerOption(I_CommandLineOption *option)
161 {
162 mOptions[ option->getName() ] = option;
163 }
164
165 void unregisterOption(I_CommandLineOption *option)
166 {
167 OptionIterator it = mOptions.find( option->getName() );
168 if (it != mOptions.end() && (*it).second == option)
169 {
170 mOptions.erase( it );
171 }
172 }
173
174 void clear()
175 {
176 mOptions.clear();
177 mOptionValues.clear();
178 mArgs.clear();
179 }
180
181 template<typename T>
182 T get(std::string name)
183 {
184 T t;
185 lexical_cast( mOptionValues[name][0], t );
186 return t;
187 }
188
189 const std::vector<std::string> &getArguments()
190 {
191 return mArgs;
192 }
193
194 const std::vector<std::string> &getValues(std::string name)
195 {
196 return mOptionValues[name];
197 }
198
199 template<typename T>
200 T lexical_cast(std::string strValue, T* = NULL)
201 {
202 T t;
203 //t = boost::lexical_cast<T, std::string>(strValue);
204 lexical_cast(strValue, t);
205 return t;
206 }
207
208 private:
209
210 std::map< std::string, I_CommandLineOption *> mOptions;
211 std::map<std::string, std::vector<std::string> > mOptionValues;
212 std::vector<std::string> mArgs;
213
214 typedef std::map< std::string, I_CommandLineOption *>::iterator OptionIterator;
215 typedef std::map<std::string, std::vector<std::string> >::iterator OptionValueIterator;
216 typedef std::vector<std::string>::iterator ValueIterator;
217
218 bool isKey(const std::string &arg)
219 {
220 bool startsWithDash = (arg.size() > 1 && arg[0] == '-' );
221 bool startsWithDoubleDash = (arg.size() > 2 && arg[0] == '-' && arg[1] == '-');
222 return startsWithDash || startsWithDoubleDash;
223 }
224
225 std::string toKey(const std::string &arg)
226 {
227 assert( isKey(arg) );
228
229 bool startsWithDash = (arg.size() > 1 && arg[0] == '-' );
230 bool startsWithDoubleDash = (arg.size() > 2 && arg[0] == '-' && arg[1] == '-');
231
232 if (startsWithDoubleDash)
233 {
234 return arg.substr(2);
235 }
236 else if (startsWithDash)
237 {
238 return arg.substr(1);
239 }
240 else
241 {
242 assert(0 && "invalid command line option syntax");
243 return "";
244 }
245 }
246
247 void lexical_cast( const std::string &strValue, bool &value )
248 {
249 if (strValue == "1" || strValue == "true" || strValue == "")
250 value = true;
251 else
252 value = false;
253 }
254
255 void lexical_cast( const std::string &strValue, int &value )
256 {
257 value = atoi(strValue.c_str());
258 }
259
260 void lexical_cast( const std::string &strValue, unsigned int &value )
261 {
262 value = static_cast<unsigned int>(atoi(strValue.c_str()));
263 }
264
265 void lexical_cast( const std::string &strValue, std::string &value )
266 {
267 value = strValue;
268 }
269
270 };
271
272 template<typename T>
273 class CommandLineOption : public I_CommandLineOption {
274 public:
275
276 CommandLineOption(std::string name, T default_value, std::string helpString) :
277 name(name), default_value(default_value), helpString(helpString)
278 {
279 CommandLine::getSingleton().registerOption(this);
280 }
281
282 ~CommandLineOption()
283 {
284 CommandLine::getSingleton().unregisterOption(this);
285 }
286
287 operator T() const
288 {
289 return get();
290 }
291
292 //const std::vector<std::string> &getValues() const
293 const std::vector<T> &getValues() const
294 {
295 return values;
296 }
297
298 T get() const
299 {
300 return (values.empty()) ? default_value : values[0];
301 }
302
303 void set(T t)
304 {
305 values.clear();
306 values.push_back( t );
307 }
308
309 virtual void on_notify_end()
310 {}
311
312 private:
313
314 void notify_begin()
315 {
316 values.clear();
317 }
318
319 void notify_end()
320 {
321 on_notify_end();
322 }
323
324 void notify( std::string value )
325 {
326 //values.push_back( CommandLine::getSingleton().template lexical_cast<T>(value) );
327 values.push_back( CommandLine::getSingleton().lexical_cast(value, (T *) 0));
328 }
329
330 std::string getName()
331 {
332 return name;
333 }
334
335 std::string getHelpString()
336 {
337 return helpString;
338 }
339
340 std::string getDefaultValue()
341 {
342 std::ostringstream ostr;
343 ostr << default_value ;
344 return ostr.str();
345 }
346
347 private:
348 std::string name;
349 T default_value;
350 std::vector<T> values;
351 std::string helpString;
352 };
353
354 template<typename T>
355 inline std::istream &operator>>(std::istream &is, CommandLineOption<T> &option)
356 {
357 T t;
358 is >> t;
359 option.set(t);
360 return is;
361 }
362
363 template<typename T>
364 inline std::ostream &operator<<(std::ostream &os, CommandLineOption<T> &option)
365 {
366 os << option.get();
367 return os;
368 }
369
370 } // namespace util
371
372 #ifdef REMEMBER_TO_UNDEFINE_ASSERT
373 #undef REMEMBER_TO_UNDEFINE_ASSERT
374 #undef ASSERT
375 #endif
376
377 #endif // ! INCLUDE_UTIL_COMMANDLINE_HPP