1 mike 1.1 //BEGIN_LICENSE
2 //
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 //END_LICENSE
21 //BEGIN_HISTORY
22 mike 1.1 //
23 // Author: Michael E. Brasher
24 //
|
25 mike 1.2 // $Log: OptionManager.h,v $
|
26 mike 1.6 // Revision 1.5 2001/04/14 06:41:17 mike
27 // New
28 //
|
29 mike 1.5 // Revision 1.4 2001/04/14 03:37:16 mike
30 // Added new example to test option manager
31 //
|
32 mike 1.4 // Revision 1.3 2001/04/14 02:26:42 mike
33 // More on option manager implementation
34 //
|
35 mike 1.3 // Revision 1.2 2001/04/14 02:11:41 mike
36 // New option manager class.
37 //
|
38 mike 1.2 // Revision 1.1 2001/04/14 01:52:45 mike
39 // New option management class.
40 //
|
41 mike 1.1 //
42 //END_HISTORY
43
44 #ifndef Pegasus_OptionManager_h
45 #define Pegasus_OptionManager_h
46
47 #include <Pegasus/Common/Config.h>
48 #include <Pegasus/Common/String.h>
49 #include <Pegasus/Common/Array.h>
|
50 mike 1.4 #include <Pegasus/Common/Exception.h>
|
51 mike 1.1
52 PEGASUS_NAMESPACE_BEGIN
53
54 class Option;
|
55 mike 1.5 struct OptionRow;
|
56 mike 1.1
57 /** The OptionManager class manages a collection of program options.
58
59 <h4>Overview</h4>
60
61 A program option may be specified in one of three ways:
62
63 <ul>
64 <li>As an environment variable</li>
65 <li>In a configuration file</li>
66 <li>On the command line</li>
67 </ul>
68
69 This class provides methods for merging options from all three of these
70 sources into a single unified collection. The following example showss
71 how to merge options from a command line into the option manager.
72
73 <pre>
74 int main(int argc, char** argv)
75 {
76 OptionManager om;
77 mike 1.1
78 ...
79
80 // Merge options from the command line into the option manager's
81 // option list. Remove arguments from command line.
82
83 om.mergeCommandLine(argc, argv);
84
85 ...
86 }
87 </pre>
88
89 Methods are also provided for merging options from files and the environment
90 (see OptionManager::mergeFile(), OptionManager::mergeEnvironment()).
91
92 Before options are merged into the option manager, information on each
93 option must be registered with the option manager so that the following
94 can be resolved:
95
96 <ul>
97 <li>The option's name</li>
98 mike 1.1 <li>The default value (to be used if not specified elsewhere)</li>
99 <li>Whether the option is required</li>
|
100 mike 1.2 <li>The option's type (e.g., boolean, integer or string)</li>
|
101 mike 1.1 <li>The domain of the option if any (set of legal values)</li>
102 <li>The name the option as it appears as an environment variable</li>
103 <li>The name the option as it appears in a configuration file</li>
104 <li>The name the option as it appears on the command line</li>
105 </ul>
106
107 Here is how to regsiter an option:
108
109 <pre>
110 OptionManager om;
111
|
112 mike 1.5 Option* option = new Option("port", "80", false, Option::NATURAL_NUMBER,
|
113 mike 1.2 Array<String>(), "PEGASUS_PORT", "PORT", "p");
|
114 mike 1.1
115 om.registerOption(option);
116 </pre>
117
118 The arguments of the Option constructor are the same (and in the same
|
119 mike 1.2 order) as the list just above. Notice that option name is "port", Whereas
120 the environment variable is named "PEGASUS_PORT" and the option name
121 in the configuration file is "port" and the command line option argument
122 name is "p" (will appear as -p on the command line).
|
123 mike 1.1
124 Once options have been registered, the option values may be obtained using
125 the merge methods described earlier. During merging, certain validation is
126 done using the corresponding Option instance described above.
127
128 Once options have been merged, they may obtained by calling the
129 lookupOption() method like this:
130
131 <pre>
132 Option* option = om.lookupOption("port");
133
134 String port = option->getValue();
135 </pre>
136
137 <h4>Command Line Options</h4>
138
139 To merge option values from the command line argument, call
140 mergeCommandLine() like this:
141
142 <pre>
143 om.mergeCommandLine(argc, argv);
144 mike 1.1 </pre>
145
146 This method searches the command line for options that match the registered
147 ones. It will extract those options from the command line (argc and argv
148 will be modified accordingly).
149
150 <h4>Configuration File Otpions</h4>
151
152 Options from a configuration file may be merged by calling the mergeFile()
153 method like this:
154
155 <pre>
156 om.mergeFile(fileName);
157 </pre>
158
159 This searches the file for options matching registered ones. Exceptions
160 are thrown for any unrecognized option names that are encountered.
161
162 <h4>Environment Variable Options</h4>
163
164 The mergeEnvironment() method merges options from the enviroment space of
165 mike 1.1 the process.
166
167 <h4>Merge Validation</h4>
168
169 During merging, the option manager validates the following (using the
170 information optatined during option registration).
171
172 <ul>
173 <li>The type of the option - whether integer, positive integer,
174 or string.</li>
175 <li>The domain of the option - whether the supplied option is a legal
176 value for that otpion</li>
177 <li>User extended validation - whether the user overriden
178 Option::isValid() returns true when the value is passed to it</li>
179 </ul>
|
180 mike 1.2
181 <h4>Typcial Usage</h4>
182
183 The OptionManager is typically used in the following way. First, options
184 are registered to establish the valid set of options. Next, values are
185 merged from the various sources by calling the merge functions. Finally,
186 checkRequiredOptions() is called to see if any required option values were
187 not provided.
|
188 mike 1.1 */
|
189 mike 1.2 class PEGASUS_COMMON_LINKAGE OptionManager
|
190 mike 1.1 {
191 public:
192
193 /** Constructor. */
194 OptionManager();
195
196 /** Destructor. Deletes all contained Options. */
197 ~OptionManager();
198
199 /** Registers an option. The OptionManager is responsible for disposing
200 of the option; the caller must not delete this object.
201
202 @param option - option to be registerd.
|
203 mike 1.5 @throw NullPointer excpetion is option argument is null.
204 @throw DuplicateOption is option already defined.
205 */
206 void registerOption(Option* option);
207
208 /** Provides a simple way to register several options at once using
209 a declartive style table. This may also be done programmitically
210 by repeatedly calling registerOption above. See documentation for
211 OptionRow for details on how to use them.
|
212 mike 1.1 */
|
213 mike 1.5 void registerOptions(OptionRow* options, Uint32 numOptions);
|
214 mike 1.1
215 /** Merge option values from the command line. Searches the command
216 line for registered options whose names are given by the
217 Option::getCommandLineOptionName() method. Validation is performed
218 on each option value obtained by calling Option::isValid(). Valid
219 option values are set by calling Option::setValue(). The argc and
220 argv arguments are modified: the option and its argument are
221 stripped from the command line. The option and its argument have the
222 following form: -option-name argument. A space must be supplied
223 between the two. Boolean option arguments are an exception. They
224 must have the form -option. If they are present, then they are
225 taken to be true.
226
227 ¶m argc - number of argument on the command line.
228 ¶m argv - list of command line arguments.
|
229 mike 1.5 &throw InvalidOptionValue when validation fails.
|
230 mike 1.4 &throw MissingCommandLineOptionArgument
|
231 mike 1.1 */
232 void mergeCommandLine(int& argc, char**& argv);
233
234 /** Merge option values from the environment. Searches the environment
235 for registered options whose names are given by the
236 Option::getEnvironmentVariableName() method. Validation is performed
237 on each option value obtained by calling Option::isValid(). Valid
238 option values are set by calling Option::setValue().
239
240 &throw BadEnvironmentOption when validation fails.
241 */
242 void mergeEnvironment();
243
244 /** Merge option values from a file. Searches file for registered options
245 whose names are given by the Option::getEnvironmentVariableName()
246 method. Validation is performed on each option value by calling
247 Option::isValid(). Valid option values are set by calling
248 Option::setValue().
249
250 ¶m fileName - name of file to be merged.
251 &throw NoSuchFile
252 mike 1.1 &throw BadConfigFileOption
253 */
254 void mergeFile(const String& fileName);
255
256 /** After merging, this method is called to check for required options
257 that were not merged (specified).
258
259 &throw UnspecifiedRequiredOption
260 */
261 void checkRequiredOptions() const;
262
|
263 mike 1.2 /** Lookup the option with the given name.
|
264 mike 1.4 @return 0 if no such option.
|
265 mike 1.2 */
|
266 mike 1.4 const Option* lookupOption(const String& name) const;
|
267 mike 1.3
|
268 mike 1.6 /** Lookup value of an option.
269 */
270 Boolean lookupValue(const String& name, String& value) const;
271
|
272 mike 1.3 /** Print all the options. */
273 void print() const;
|
274 mike 1.2
|
275 mike 1.1 private:
276
|
277 mike 1.4 /** Lookup the option by its commandLineOptionName.
278 @return 0 if no such option.
279 */
280 Option* _lookupOptionByCommandLineOptionName(const String& name);
281
|
282 mike 1.6 /** Lookup the option by its configFileOptionName.
283 @return 0 if no such option.
284 */
285 Option* _lookupOptionByConfigFileOptionName(const String& name);
286
|
287 mike 1.1 Array<Option*> _options;
288 };
289
290 /** The Option class is used to specify information about an Option.
291
292 See the OptionManager class for more details.
293 */
|
294 mike 1.2 class PEGASUS_COMMON_LINKAGE Option
|
295 mike 1.1 {
296 public:
297
298 /** Valid value types. */
|
299 mike 1.5 enum Type
300 {
301 // (..., -3, -2, -1, 0, 1, 2, 3, ...)
302 INTEGER,
303
304 // (1, 2, 3, ...)
305 NATURAL_NUMBER,
306
307 // (0, 1, 2, 3, ...)
308 WHOLE_NUMBER,
309
310 // "true" or "false"
311 BOOLEAN,
312
313 // Anything
314 STRING
315 };
|
316 mike 1.1
317 // Hack to fix bug in MSVC.
318 typedef Array<String> StringArray;
319
320 /** Constructor.
321
322 @param optionName - the name of this option.
323
324 @param defaultValue - the default value of this option.
325
326 @param required - whether the value of this option is required.
327
328 @param type - type of the value. This is used to validate the value.
329
330 @param domain - list of legal value for this option. If this list
331 is empty, then no domain is enforced.
332
333 @param environmentVariableName - name of the corresponding environment
334 variable (which may be different from the option name).
335
|
336 mike 1.6 @param configFileOptionName - name of the corresponding variable
|
337 mike 1.1 in the config file (which may be different from the option name).
338
339 @param commandLineOptionName - name of the corresponding command line
340 option (which may be different from the option name).
341 */
342 Option(
343 const String& optionName,
344 const String& defaultValue,
345 Boolean required,
346 Type type,
347 const StringArray& domain = StringArray(),
348 const String& environmentVariableName = String(),
|
349 mike 1.6 const String& configFileOptionName = String(),
|
350 mike 1.2 const String& commandLineOptionName = String());
351
352 Option(const Option& x);
|
353 mike 1.1
354 virtual ~Option();
355
|
356 mike 1.2 Option& operator=(const Option& x);
|
357 mike 1.1
358 /** Accessor */
359 const String& getOptionName() const
360 {
361 return _optionName;
362 }
363
364 /** Modifier */
365 void setOptionName(const String& optionName)
366 {
367 _optionName = optionName;
368 }
369
370 /** Accessor */
371 const String& getDefaultValue() const
372 {
373 return _defaultValue;
374 }
375
376 /** Modifier. */
377 void setDefaultValue(const String& defaultValue)
378 mike 1.1 {
379 _defaultValue = defaultValue;
380 }
381
382 /** Accessor */
383 const String& getValue() const
384 {
385 return _value;
386 }
387
388 /** Modifier */
389 void setValue(const String& value)
390 {
391 _value = value;
392 }
393
394 /** Accessor */
395 Boolean getRequired() const
396 {
397 return _required;
398 }
399 mike 1.1
400 /** Modifier */
401 void setRequired(Boolean required)
402 {
403 _required = required;
404 }
405
406 /** Accessor */
407 Type getType() const
408 {
409 return _type;
410 }
411
412 /** Modifier */
413 void setType(Type type)
414 {
415 _type = type;
416 }
417
418 /** Accessor */
419 const StringArray& getDomain() const
420 mike 1.1 {
421 return _domain;
422 }
423
424 /** Modifier */
425 void setDomain(const StringArray& domain)
426 {
427 _domain = domain;
428 }
429
430 /** Accessor */
431 const String& getEnvironmentVariableName() const
432 {
433 return _environmentVariableName;
434 }
435
436 /** Modifier */
437 void setEnvironmentVariableName(const String& environmentVariableName)
438 {
439 _environmentVariableName = environmentVariableName;
440 }
441 mike 1.1
442 /** Accessor */
|
443 mike 1.6 const String& getConfigFileOptionName() const
|
444 mike 1.1 {
|
445 mike 1.6 return _configFileOptionName;
|
446 mike 1.1 }
447
448 /** Modifier */
|
449 mike 1.6 void setConfigFileOptionName(const String& configFileOptionName)
|
450 mike 1.1 {
|
451 mike 1.6 _configFileOptionName = configFileOptionName;
|
452 mike 1.1 }
453
454 /** Accessor */
455 const String& getCommandLineOptionName() const
456 {
457 return _commandLineOptionName;
458 }
459
460 /** Modifier */
461 void setCommandLineOptionName(const String& commandLineOptionName)
462 {
463 _commandLineOptionName = commandLineOptionName;
464 }
465
466 /** Accesor. Returns true if an option value was ever obtained for
467 this option.
468 */
469 Boolean foundValue() const
470 {
471 return _foundValue;
472 }
473 mike 1.1
474 /** Checks to see if the given value is valid or not. This method may be
475 overriden by derived classes to do special purpose validation of the
476 value. This implementation just checks the domain and type.
477 */
478 virtual Boolean isValid(const String& value) const;
479
480 private:
481 String _optionName;
482 String _defaultValue;
483 String _value;
484 Boolean _required;
485 Type _type;
486 StringArray _domain;
487 String _environmentVariableName;
|
488 mike 1.6 String _configFileOptionName;
|
489 mike 1.1 String _commandLineOptionName;
490 Boolean _foundValue;
|
491 mike 1.4 };
492
|
493 mike 1.5 /** The OptionRow provides a declarative way of defining Option objects.
494 For the declarative programming enthusiast, we provide this structure.
495 It provides a declarative way of defining options for the OptionManager
496 class. Some developers prefer this since it makes all the options visible
497 in a kind of table like structure. Here is an example of how it can be
498 used to define a port number and hostname options. We also show how to
499 register one of these option lists with an OptionManager.
500
501 <pre>
502 static OptionRow options[] =
503 {
504 { "port", "80", false, Option::NATURAL_NUMBER },
505 { "hostname", "", true, Option::STRING }
506 };
507
508 ...
509
510 OptionManager om;
511 om.registerOptions(options, sizeof(options) / sizeof(options[0]));
512 </pre>
513
514 mike 1.5 Recall that static memory areas are initialized with zeros so that the
515 members that are not initialized explicitly in the example above are
516 initialized implicitly with zeros (which the OptionManager used to
517 determine that they are not used).
518
519 It is possible to specify domains as well. For example, suppose we
520 want to define a "color" option that can be in the following set:
521 {"red", "green", "blue"}. Here is how to express that:
522
523 <pre>
524 static const char* colors[] = { "red", "green", "blue" };
525
526 static OptionRow options[] =
527 {
528 { "color", "red", false, Option::STRING, colors, 3 }
529 };
530 </pre>
531 */
532 struct OptionRow
533 {
534 const char* optionName;
535 mike 1.5 const char* defaultValue;
536 Boolean required;
537 Option::Type type;
538 char** domain;
539 Uint32 domainSize;
540 const char* environmentVariableName;
|
541 mike 1.6 const char* configFileOptionName;
|
542 mike 1.5 const char* commandLineOptionName;
543 };
544
545 /** Exception class */
|
546 mike 1.4 class MissingCommandLineOptionArgument : public Exception
547 {
548 public:
549
550 MissingCommandLineOptionArgument(const String& optionName)
551 : Exception("Missing command line option argument: " + optionName) { }
552 };
553
|
554 mike 1.5 /** Exception class */
555 class InvalidOptionValue : public Exception
556 {
557 public:
558
559 InvalidOptionValue(const String& name, const String& value)
560 : Exception("Invalid option value: " + name + "=\"" + value + "\"") { }
561 };
562
563 /** Exception class */
564 class DuplicateOption : public Exception
|
565 mike 1.4 {
566 public:
567
|
568 mike 1.5 DuplicateOption(const String& name)
569 : Exception("Duplicate option: " + name) { }
|
570 mike 1.6 };
571
572 /** Exception class */
573 class ConfigFileSyntaxError : public Exception
574 {
575 public:
576
577 ConfigFileSyntaxError(const String& file, Uint32 line)
578 : Exception(_formatMessage(file, line)) { }
579
580 static String _formatMessage(const String& file, Uint32 line);
581 };
582
583 /** Exception class */
584 class UnrecognizedConfigFileOption : public Exception
585 {
586 public:
587
588 UnrecognizedConfigFileOption(const String& name)
589 : Exception("Unrecognized config file option: " + name) { }
|
590 mike 1.1 };
591
592 PEGASUS_NAMESPACE_END
593
594 #endif /* Pegasus_OptionManager_h */
|