1 mike 1.10 //%/////////////////////////////////////////////////////////////////////////////
|
2 mike 1.1 //
3 // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 // DEALINGS IN THE SOFTWARE.
19 //
|
20 mike 1.10 //==============================================================================
|
21 mike 1.1 //
|
22 mike 1.10 // Author: Mike Brasher (mbrasher@bmc.com)
|
23 mike 1.1 //
|
24 mike 1.10 // Modified By:
|
25 mike 1.9 //
|
26 mike 1.10 //%/////////////////////////////////////////////////////////////////////////////
|
27 mike 1.1
28 #ifndef Pegasus_OptionManager_h
29 #define Pegasus_OptionManager_h
30
31 #include <Pegasus/Common/Config.h>
32 #include <Pegasus/Common/String.h>
33 #include <Pegasus/Common/Array.h>
|
34 mike 1.4 #include <Pegasus/Common/Exception.h>
|
35 mike 1.1
36 PEGASUS_NAMESPACE_BEGIN
37
38 class Option;
|
39 mike 1.5 struct OptionRow;
|
40 mike 1.1
41 /** The OptionManager class manages a collection of program options.
42
43 <h4>Overview</h4>
44
|
45 mike 1.9 A program option may be specified in two ways:
|
46 mike 1.1
47 <ul>
48 <li>In a configuration file</li>
49 <li>On the command line</li>
50 </ul>
51
|
52 mike 1.9 This class provides methods for merging options from both of these
53 sources into a single collection. The following example shows how to
54 merge options from a command line into the option manager.
|
55 mike 1.1
56 <pre>
57 int main(int argc, char** argv)
58 {
59 OptionManager om;
60
61 ...
62
63 // Merge options from the command line into the option manager's
64 // option list. Remove arguments from command line.
65
66 om.mergeCommandLine(argc, argv);
67
68 ...
69 }
70 </pre>
71
|
72 mike 1.9 Similarly, the OptionManager::mergeFile() method allows options to be
73 merged from a file.
|
74 mike 1.1
75 Before options are merged into the option manager, information on each
76 option must be registered with the option manager so that the following
77 can be resolved:
78
79 <ul>
80 <li>The option's name</li>
81 <li>The default value (to be used if not specified elsewhere)</li>
82 <li>Whether the option is required</li>
|
83 mike 1.2 <li>The option's type (e.g., boolean, integer or string)</li>
|
84 mike 1.1 <li>The domain of the option if any (set of legal values)</li>
85 <li>The name the option as it appears on the command line</li>
86 </ul>
87
88 Here is how to regsiter an option:
89
90 <pre>
91 OptionManager om;
92
|
93 mike 1.9 Option* option = new Option("port", "80", false,
94 Option::NATURAL_NUMBER, Array<String>(), "p");
|
95 mike 1.1
96 om.registerOption(option);
97 </pre>
98
99 The arguments of the Option constructor are the same (and in the same
|
100 mike 1.9 order) as the list just above. Notice the last argument is "p". This
101 is the name of the option argument on the command line (it would appear
102 as "-p" on the command line).
103
104 Once options have been registered, the option values may be initialized
105 using the merge methods described earlier. During merging, certain
106 validation is done using the corresponding Option instance described above.
|
107 mike 1.1
108 Once options have been merged, they may obtained by calling the
109 lookupOption() method like this:
110
111 <pre>
112 Option* option = om.lookupOption("port");
|
113 mike 1.9 String port = option->getValue();
114 </pre>
|
115 mike 1.1
|
116 mike 1.9 Or the lookupValue() convenience function may be used to lookup values:
117
118 <pre>
119 String value;
120 om.lookupValue("port", value);
|
121 mike 1.1 </pre>
122
123 <h4>Command Line Options</h4>
124
125 mergeCommandLine() like this:
126
127 <pre>
128 om.mergeCommandLine(argc, argv);
129 </pre>
130
131 This method searches the command line for options that match the registered
132 ones. It will extract those options from the command line (argc and argv
133 will be modified accordingly).
134
135 <h4>Configuration File Otpions</h4>
136
137 Options from a configuration file may be merged by calling the mergeFile()
138 method like this:
139
140 <pre>
141 om.mergeFile(fileName);
142 mike 1.1 </pre>
143
144 This searches the file for options matching registered ones. Exceptions
145 are thrown for any unrecognized option names that are encountered.
146
147 <h4>Merge Validation</h4>
148
149 During merging, the option manager validates the following (using the
150 information optatined during option registration).
151
152 <ul>
153 <li>The type of the option - whether integer, positive integer,
|
154 mike 1.9 or string or whatever.</li>
|
155 mike 1.1 <li>The domain of the option - whether the supplied option is a legal
156 value for that otpion</li>
157 <li>User extended validation - whether the user overriden
158 Option::isValid() returns true when the value is passed to it</li>
159 </ul>
|
160 mike 1.2
161 <h4>Typcial Usage</h4>
162
163 The OptionManager is typically used in the following way. First, options
164 are registered to establish the valid set of options. Next, values are
165 merged from the various sources by calling the merge functions. Finally,
166 checkRequiredOptions() is called to see if any required option values were
167 not provided.
|
168 mike 1.1 */
|
169 mike 1.2 class PEGASUS_COMMON_LINKAGE OptionManager
|
170 mike 1.1 {
171 public:
172
173 /** Constructor. */
174 OptionManager();
175
176 /** Destructor. Deletes all contained Options. */
177 ~OptionManager();
178
179 /** Registers an option. The OptionManager is responsible for disposing
180 of the option; the caller must not delete this object.
181
|
182 mike 1.8 @param option option to be registerd.
|
183 mike 1.7 @exception NullPointer exception if option argument is null.
184 @exception DuplicateOption if option already defined.
|
185 mike 1.5 */
186 void registerOption(Option* option);
187
188 /** Provides a simple way to register several options at once using
189 a declartive style table. This may also be done programmitically
190 by repeatedly calling registerOption above. See documentation for
191 OptionRow for details on how to use them.
|
192 mike 1.1 */
|
193 mike 1.5 void registerOptions(OptionRow* options, Uint32 numOptions);
|
194 mike 1.1
195 /** Merge option values from the command line. Searches the command
196 line for registered options whose names are given by the
197 Option::getCommandLineOptionName() method. Validation is performed
198 on each option value obtained by calling Option::isValid(). Valid
199 option values are set by calling Option::setValue(). The argc and
200 argv arguments are modified: the option and its argument are
201 stripped from the command line. The option and its argument have the
202 following form: -option-name argument. A space must be supplied
203 between the two. Boolean option arguments are an exception. They
204 must have the form -option. If they are present, then they are
205 taken to be true.
206
|
207 mike 1.8 ¶m argc number of argument on the command line.
208 ¶m argv list of command line arguments.
|
209 mike 1.7 &exception InvalidOptionValue if validation fails.
210 &exception MissingCommandLineOptionArgument
|
211 mike 1.1 */
212 void mergeCommandLine(int& argc, char**& argv);
213
214 /** Merge option values from a file. Searches file for registered options
|
215 mike 1.9 whose names are given by the options which have been registered.
216 Validation is performed on each option value by calling
|
217 mike 1.1 Option::isValid(). Valid option values are set by calling
218 Option::setValue().
219
|
220 mike 1.8 ¶m fileName name of file to be merged.
|
221 mike 1.7 &exception NoSuchFile if file cannot be opened.
222 &exception BadConfigFileOption
|
223 mike 1.1 */
224 void mergeFile(const String& fileName);
225
226 /** After merging, this method is called to check for required options
227 that were not merged (specified).
228
|
229 mike 1.9 &exception MissingRequiredRequiredOption
|
230 mike 1.1 */
231 void checkRequiredOptions() const;
232
|
233 mike 1.2 /** Lookup the option with the given name.
|
234 mike 1.4 @return 0 if no such option.
|
235 mike 1.2 */
|
236 mike 1.4 const Option* lookupOption(const String& name) const;
|
237 mike 1.3
|
238 mike 1.6 /** Lookup value of an option.
239 */
240 Boolean lookupValue(const String& name, String& value) const;
241
|
242 mike 1.3 /** Print all the options. */
243 void print() const;
|
244 mike 1.2
|
245 mike 1.1 private:
246
|
247 mike 1.4 /** Lookup the option by its commandLineOptionName.
248 @return 0 if no such option.
249 */
250 Option* _lookupOptionByCommandLineOptionName(const String& name);
251
|
252 mike 1.1 Array<Option*> _options;
253 };
254
255 /** The Option class is used to specify information about an Option.
256
257 See the OptionManager class for more details.
258 */
|
259 mike 1.2 class PEGASUS_COMMON_LINKAGE Option
|
260 mike 1.1 {
261 public:
262
263 /** Valid value types. */
|
264 mike 1.5 enum Type
265 {
266 // (..., -3, -2, -1, 0, 1, 2, 3, ...)
267 INTEGER,
268
269 // (1, 2, 3, ...)
270 NATURAL_NUMBER,
271
272 // (0, 1, 2, 3, ...)
273 WHOLE_NUMBER,
274
275 // "true" or "false"
276 BOOLEAN,
277
278 // Anything
279 STRING
280 };
|
281 mike 1.1
282 // Hack to fix bug in MSVC.
283 typedef Array<String> StringArray;
284
285 /** Constructor.
286
|
287 mike 1.8 @param optionName the name of this option.
|
288 mike 1.1
|
289 mike 1.8 @param defaultValue the default value of this option.
|
290 mike 1.1
|
291 mike 1.8 @param required whether the value of this option is required.
|
292 mike 1.1
|
293 mike 1.8 @param type type of the value. This is used to validate the value.
|
294 mike 1.1
|
295 mike 1.8 @param domain list of legal value for this option. If this list
|
296 mike 1.1 is empty, then no domain is enforced.
297
|
298 mike 1.8 @param commandLineOptionName name of the corresponding command line
|
299 mike 1.1 option (which may be different from the option name).
300 */
301 Option(
302 const String& optionName,
303 const String& defaultValue,
304 Boolean required,
305 Type type,
306 const StringArray& domain = StringArray(),
|
307 mike 1.2 const String& commandLineOptionName = String());
308
309 Option(const Option& x);
|
310 mike 1.1
311 virtual ~Option();
312
|
313 mike 1.2 Option& operator=(const Option& x);
|
314 mike 1.1
315 /** Accessor */
316 const String& getOptionName() const
317 {
318 return _optionName;
319 }
320
321 /** Modifier */
322 void setOptionName(const String& optionName)
323 {
324 _optionName = optionName;
325 }
326
327 /** Accessor */
328 const String& getDefaultValue() const
329 {
330 return _defaultValue;
331 }
332
333 /** Modifier. */
334 void setDefaultValue(const String& defaultValue)
335 mike 1.1 {
336 _defaultValue = defaultValue;
337 }
338
339 /** Accessor */
340 const String& getValue() const
341 {
342 return _value;
343 }
344
345 /** Modifier */
346 void setValue(const String& value)
347 {
348 _value = value;
|
349 mike 1.9 _resolved = true;
|
350 mike 1.1 }
351
352 /** Accessor */
353 Boolean getRequired() const
354 {
355 return _required;
356 }
357
358 /** Modifier */
359 void setRequired(Boolean required)
360 {
361 _required = required;
362 }
363
364 /** Accessor */
365 Type getType() const
366 {
367 return _type;
368 }
369
370 /** Modifier */
371 mike 1.1 void setType(Type type)
372 {
373 _type = type;
374 }
375
376 /** Accessor */
377 const StringArray& getDomain() const
378 {
379 return _domain;
380 }
381
382 /** Modifier */
383 void setDomain(const StringArray& domain)
384 {
385 _domain = domain;
386 }
387
388 /** Accessor */
389 const String& getCommandLineOptionName() const
390 {
391 return _commandLineOptionName;
392 mike 1.1 }
393
394 /** Modifier */
395 void setCommandLineOptionName(const String& commandLineOptionName)
396 {
397 _commandLineOptionName = commandLineOptionName;
398 }
399
400 /** Accesor. Returns true if an option value was ever obtained for
401 this option.
402 */
|
403 mike 1.9 Boolean isResolved() const
404 {
405 return _resolved;
|
406 mike 1.1 }
407
408 /** Checks to see if the given value is valid or not. This method may be
409 overriden by derived classes to do special purpose validation of the
410 value. This implementation just checks the domain and type.
411 */
412 virtual Boolean isValid(const String& value) const;
413
414 private:
415 String _optionName;
416 String _defaultValue;
417 String _value;
418 Boolean _required;
419 Type _type;
420 StringArray _domain;
421 String _commandLineOptionName;
|
422 mike 1.9 Boolean _resolved;
|
423 mike 1.4 };
424
|
425 mike 1.5 /** The OptionRow provides a declarative way of defining Option objects.
426 For the declarative programming enthusiast, we provide this structure.
427 It provides a declarative way of defining options for the OptionManager
428 class. Some developers prefer this since it makes all the options visible
429 in a kind of table like structure. Here is an example of how it can be
430 used to define a port number and hostname options. We also show how to
431 register one of these option lists with an OptionManager.
432
433 <pre>
434 static OptionRow options[] =
435 {
436 { "port", "80", false, Option::NATURAL_NUMBER },
437 { "hostname", "", true, Option::STRING }
438 };
439
440 ...
441
442 OptionManager om;
443 om.registerOptions(options, sizeof(options) / sizeof(options[0]));
444 </pre>
445
446 mike 1.5 Recall that static memory areas are initialized with zeros so that the
447 members that are not initialized explicitly in the example above are
448 initialized implicitly with zeros (which the OptionManager used to
449 determine that they are not used).
450
451 It is possible to specify domains as well. For example, suppose we
452 want to define a "color" option that can be in the following set:
453 {"red", "green", "blue"}. Here is how to express that:
454
455 <pre>
456 static const char* colors[] = { "red", "green", "blue" };
|
457 mike 1.9 static const Uint32 NUM_COLORS = sizeof(colors) / sizeof(colors[0]);
|
458 mike 1.5
459 static OptionRow options[] =
460 {
|
461 mike 1.9 { "color", "red", false, Option::STRING, colors, NUM_COLORS }
|
462 mike 1.5 };
463 </pre>
464 */
465 struct OptionRow
466 {
467 const char* optionName;
468 const char* defaultValue;
469 Boolean required;
470 Option::Type type;
471 char** domain;
472 Uint32 domainSize;
473 const char* commandLineOptionName;
474 };
475
476 /** Exception class */
|
477 mike 1.4 class MissingCommandLineOptionArgument : public Exception
478 {
479 public:
480
481 MissingCommandLineOptionArgument(const String& optionName)
482 : Exception("Missing command line option argument: " + optionName) { }
483 };
484
|
485 mike 1.5 /** Exception class */
486 class InvalidOptionValue : public Exception
487 {
488 public:
489
490 InvalidOptionValue(const String& name, const String& value)
491 : Exception("Invalid option value: " + name + "=\"" + value + "\"") { }
492 };
493
494 /** Exception class */
495 class DuplicateOption : public Exception
|
496 mike 1.4 {
497 public:
498
|
499 mike 1.5 DuplicateOption(const String& name)
500 : Exception("Duplicate option: " + name) { }
|
501 mike 1.6 };
502
503 /** Exception class */
504 class ConfigFileSyntaxError : public Exception
505 {
506 public:
507
508 ConfigFileSyntaxError(const String& file, Uint32 line)
509 : Exception(_formatMessage(file, line)) { }
510
511 static String _formatMessage(const String& file, Uint32 line);
512 };
513
514 /** Exception class */
515 class UnrecognizedConfigFileOption : public Exception
516 {
517 public:
518
519 UnrecognizedConfigFileOption(const String& name)
520 : Exception("Unrecognized config file option: " + name) { }
|
521 mike 1.9 };
522
523 /** Exception class */
524 class MissingRequiredOptionValue : public Exception
525 {
526 public:
527
528 MissingRequiredOptionValue(const String& name)
529 : Exception("Missing required option value: " + name) { }
|
530 mike 1.1 };
531
532 PEGASUS_NAMESPACE_END
533
534 #endif /* Pegasus_OptionManager_h */
|