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