1 mike 1.23 //%/////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001 The Open group, BMC Software, Tivoli Systems, IBM
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to
7 // deal in the Software without restriction, including without limitation the
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 // sell copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
13 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
14 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 //
21 //==============================================================================
22 mike 1.23 //
23 // Author: Mike Brasher (mbrasher@bmc.com)
24 //
|
25 karl 1.27 // Modified By: Karl Schopmyer(k.schopmeyer@opengroup.org)
|
26 mike 1.23 //
27 //%/////////////////////////////////////////////////////////////////////////////
28
29 //////////////////////////////////////////////////////////////////////////////
30 //
31 // This file defines the classes necessary to manage commandline and
32 // configuration file options for Pegasus. It defines
33 // The OptionManager Class
34 // The Option Class - Used to define information about an option
35 // The Option Row structure - Used to define option declarations in a
36 // program
37 // The optionexcptions Class
38 //
39 //////////////////////////////////////////////////////////////////////////////
40
41 #ifndef Pegasus_OptionManager_h
42 #define Pegasus_OptionManager_h
43
44 #include <Pegasus/Common/Config.h>
45 #include <Pegasus/Common/String.h>
46 #include <Pegasus/Common/Array.h>
47 mike 1.23 #include <Pegasus/Common/Exception.h>
48
49 PEGASUS_NAMESPACE_BEGIN
50
51 class Option;
52 struct OptionRow;
53
54 typedef Option* OptionPtr;
55
|
56 mike 1.24 // REVIEW: I seem to remember seeing another class that does something like
57 // REVIEW: this.
|
58 mike 1.23
59 /** The OptionManager class manages a collection of program options.
60
61 <h4>Overview</h4>
62
63 A program option may be specified in two ways:
64
65 <ul>
66 <li>In a configuration file</li>
67 <li>On the command line</li>
68 </ul>
69
70 This class provides methods for merging options from both of these
71 sources into a single collection. The following example shows how to
72 merge options from a command line into the option manager.
73
74 <pre>
75 int main(int argc, char** argv)
76 {
77 OptionManager om;
78
79 mike 1.23 ...
80
81 // Merge options from the command line into the option manager's
82 // option list. Remove arguments from command line.
83
84 om.mergeCommandLine(argc, argv);
85
86 ...
87 }
88 </pre>
89
90 Similarly, the OptionManager::mergeFile() method allows options to be
91 merged from a file.
92
93 Before options are merged into the option manager, information on each
94 option must be registered with the option manager so that the following
95 can be resolved:
96
97 <ul>
98 <li>The option's name</li>
99 <li>The default value (to be used if not specified elsewhere)</li>
100 mike 1.23 <li>Whether the option is required</li>
101 <li>The option's type (e.g., boolean, integer or string)</li>
102 <li>The domain of the option if any (set of legal values)</li>
103 <li>The name the option as it appears on the command line</li>
104 </ul>
105
106 Here is how to regsiter an option:
107
108 <pre>
109 OptionManager om;
110
111 Option* option = new Option("port", "80", false,
112 Option::NATURAL_NUMBER, Array<String>(), "p");
113
114 om.registerOption(option);
115 </pre>
116
117 The arguments of the Option constructor are the same (and in the same
118 order) as the list just above. Notice the last argument is "p". This
119 is the name of the option argument on the command line (it would appear
120 as "-p" on the command line).
121 mike 1.23
122 Once options have been registered, the option values may be initialized
123 using the merge methods described earlier. During merging, certain
124 validation is done using the corresponding Option instance described above.
125
126 Once options have been merged, they may obtained by calling the
127 lookupOption() method like this:
128
129 <pre>
130 Option* option = om.lookupOption("port");
131 String port = option->getValue();
132 </pre>
133
134 Or the lookupValue() convenience function may be used to lookup values:
135
136 <pre>
137 String value;
138 om.lookupValue("port", value);
139 </pre>
|
140 karl 1.27
141 Boolean Options can easily be tested as follows:
142 <pre>
143
144 </pre>
|
145 mike 1.23
146 <h4>Command Line Options</h4>
147
148 mergeCommandLine() like this:
149
150 <pre>
151 om.mergeCommandLine(argc, argv);
152 </pre>
153
154 This method searches the command line for options that match the registered
155 ones. It will extract those options from the command line (argc and argv
156 will be modified accordingly).
157
158 <h4>Configuration File Otpions</h4>
159
160 Options from a configuration file may be merged by calling the mergeFile()
161 method like this:
162
163 <pre>
164 om.mergeFile(fileName);
165 </pre>
166 mike 1.23
167 This searches the file for options matching registered ones. Exceptions
168 are thrown for any unrecognized option names that are encountered.
169
170 <h4>Merge Validation</h4>
171
172 During merging, the option manager validates the following (using the
173 information optatined during option registration).
174
175 <ul>
176 <li>The type of the option - whether integer, positive integer,
177 or string or whatever.</li>
178 <li>The domain of the option - whether the supplied option is a legal
179 value for that otpion</li>
180 <li>User extended validation - whether the user overriden
181 Option::isValid() returns true when the value is passed to it</li>
182 </ul>
183
184 <h4>Typcial Usage</h4>
185
186 The OptionManager is typically used in the following way. First, options
187 mike 1.23 are registered to establish the valid set of options. Next, values are
188 merged from the various sources by calling the merge functions. Finally,
189 checkRequiredOptions() is called to see if any required option values were
190 not provided.
191
192 <h4>Option Types</h4>
193
194 The option manager allows for several types of options including:
195 <UL>
196 <LI> (BOOLEAN)Simple keyword parameters (ex. -t or -h on the command
197 line). These are Boolean parameters and there are no additional parameters
198 after the keyword.
199
200 <LI> (INTEGER) Numeric parameters - (ex -port 5988). These are
201 parameters where a numeric variable follows the parameter defintion.
202
203 <LI>(WHOLE_NUMBER) Numeric parameters ATTN: Finish.
204
205 <LI> (NATURAL_NUMBER Numieric parameters - (ex ). ATTN: finish
206
207 <LI>(STRING) String Parameters - (ex. -file abd.log) These are
208 mike 1.23 parameters that are represented by strings following the option
209 keyword. No limitations are placed on the string except that it must
210 be resolvable to a single string.
211
212 <LI> (STRING) Domain Parameters - These are parameters where there is
213 a choice of keywords from a domain of keywords. The input parameter may be any
214 one of these keywords. Thus, the domain (red blue green) for the
215 parameter "color" (-c) could be entered as -c red. The difference
216 between String interpretation and domain interpretation is the use of the
217 domain fields in the option definition.
218
219 <LI> Mask parameters - These are parameters that define an internal
220 bit mask from a set of keywords input.
221 ATTN: Finish this definition.
222 </UL>
223 */
224
225 class PEGASUS_COMMON_LINKAGE OptionManager
226 {
227 public:
228
229 mike 1.23 /** Constructor. */
230 OptionManager();
231
232 /** Destructor. Deletes all contained Options. */
233 ~OptionManager();
234
235 /** Registers an option. The OptionManager is responsible for disposing
236 of the option; the caller must not delete this object.
237
238 @param option option to be registerd.
239 @exception NullPointer exception if option argument is null.
|
240 karl 1.27 @exception OMDuplicateOption if option already defined.
|
241 mike 1.23 */
|
242 karl 1.27 void registerOption(Option* option);
243 // throw(NullPointer, OMDuplicateOption);
|
244 mike 1.23
245 /** Provides a simple way to register several options at once using
246 a declartive style table. This may also be done programmitically
247 by repeatedly calling registerOption above. See documentation for
248 OptionRow for details on how to use them.
249 */
|
250 kumpf 1.28 void registerOptions(OptionRow* options, Uint32 numOptions)
251 throw (NullPointer);
|
252 mike 1.23
253 /** Merge option values from the command line. Searches the command
254 line for registered options whose names are given by the
255 Option::getCommandLineOptionName() method. Validation is performed
256 on each option value obtained by calling Option::isValid(). Valid
257 option values are set by calling Option::setValue(). The argc and
258 argv arguments are modified: the option and its argument are
259 stripped from the command line. The option and its argument have the
260 following form: -option-name argument. A space must be supplied
261 between the two. Boolean option arguments are an exception. They
262 must have the form -option. If they are present, then they are
263 taken to be true.
264
265 ¶m argc number of argument on the command line.
266 ¶m argv list of command line arguments.
|
267 karl 1.27 ¶m abortOnErr - Optional Boolean that if true causes exception if there is
268 a parameter found that is not in the table. Defaults to true
|
269 mike 1.23 &exception InvalidOptionValue if validation fails.
|
270 karl 1.27 &exception OMMissingCommandLineOptionArgument
|
271 mike 1.23 */
|
272 karl 1.27 void mergeCommandLine(int& argc, char**& argv, Boolean abortOnErr=true);
|
273 mike 1.23
274 /** Merge option values from a file. Searches file for registered options
275 whose names are given by the options which have been registered.
276 Validation is performed on each option value by calling
277 Option::isValid(). Valid option values are set by calling
278 Option::setValue().
279
280 ¶m fileName name of file to be merged.
281 &exception NoSuchFile if file cannot be opened.
282 &exception BadConfigFileOption
283 */
284 void mergeFile(const String& fileName);
285
286 /** After merging, this method is called to check for required options
287 that were not merged (specified).
288
|
289 karl 1.27 &exception OMMissingRequiredRequiredOption
|
290 mike 1.23 */
291 void checkRequiredOptions() const;
292
293 /** Lookup the option with the given name.
294 @param Name provides the name of the option.
295 @return 0 if no such option.
296 */
297 const Option* lookupOption(const String& name) const;
298
299 /** Lookup value of an option.
300 @param Name provides the name of the option (ex. "port")
301 @param String parameter contains the String that contains the
302 value for this parameter (in String format).
303 @return Boolean return. True if the option found.
304 */
|
305 karl 1.30 Boolean lookupValue(const String& name, String& value ) const;
306
307 /** LookupIntegerValue value of an option determines if the value exists
308 and converts it to integer (Uint32).
309 @param Name provides the name of the option (ex. "port")
310 @param String parameter contains the String that contains the
311 value for this parameter (in String format).
312 @return Boolean return. True if the option found.
313 */
314 Boolean lookupIntegerValue(const String& name, Uint32& value) const;
315
|
316 mike 1.23
317 /** isStringInOptionMask - Looks for a String value in an option.
318 This function is used to detect particular options listed in strings of
319 entries forming a STRING option. Thus, for example if the option string
320 were "abc,def,ijk" in option toy isStringInOption ("toy", "def") returns
321 true.
322 @param option name of the option in the option table
323 @param entry Entry to compare
324 @return True if the entry String is found in the option.
325 */
326 //Uint32 isStringInOptionMask (const String& option, String& entry) const;
327
328 /** optionValueEquals - Test the string value of an option.
329 @param name provides the name of the option (ex. "port")
330 @param value String value for comparison.
331 @return true if the option exists and the value of the option
332 equals the input parameter value.
333 */
334 Boolean valueEquals(const String& name, const String& value) const;
335
|
336 karl 1.27 /** isTrue - determines if a Boolean Option is true or false. Note
337 that this function simply tests the value for "true" string.
338 @param name - the name of the opeiton
339 @return - Returns true if the option value is true.
340 */
341 Boolean isTrue(const String& name) const;
|
342 mike 1.23
343 /** Print all the options. */
344 void print() const;
345
346 /** Print the help line for all options including cmdline name, name
347 and the help string
348 */
|
349 karl 1.25 void printOptionsHelp() const;
350
351 /** Print Complete Help Text message including header before the options help
352 and trailer after the options help
353 */
354 void printOptionsHelpTxt(const String& header, const String& trailer) const;
|
355 mike 1.23
356
357 private:
358
359 /** Lookup the option by its commandLineOptionName.
360 @return 0 if no such option.
361 */
362 Option* _lookupOptionByCommandLineOptionName(const String& name);
363
364 Array<Option*> _options;
365 };
366
367 //////////////////////////////////////////////////////////////////
368 // OPTION CLASS
369 //////////////////////////////////////////////////////////////////
370
371 /** The Option class is used to specify information about an Option.
372
373 See the OptionManager class for more details.
374 */
375 class PEGASUS_COMMON_LINKAGE Option
376 mike 1.23 {
377 public:
378
379 /** Valid value types. */
380 enum Type
381 {
382 // (..., -3, -2, -1, 0, 1, 2, 3, ...)
383 INTEGER,
384
385 // (1, 2, 3, ...)
386 NATURAL_NUMBER,
387
388 // (0, 1, 2, 3, ...)
389 WHOLE_NUMBER,
390
391 // "true" or "false"
392 BOOLEAN,
393
394 // Anything
395 STRING
396 };
397 mike 1.23
398 /** Constructor.
399
400 @param optionName the name of this option.
401
402 @param defaultValue the default value of this option.
403
404 @param required whether the value of this option is required.
405
406 @param type type of the value. This is used to validate the value.
407
408 @param domain list of legal value for this option. If this list
409 is empty, then no domain is enforced.
410
411 @param commandLineOptionName name of the corresponding command line
412 option (which may be different from the option name).
413
414 @param optionHelpMessage Text message that defines option. To be used
415 in Usage messages.
416 */
417 Option(
418 mike 1.23 const String& optionName,
419 const String& defaultValue,
420 Boolean required,
421 Type type,
|
422 kumpf 1.29 const Array<String>& domain = Array<String>(),
|
423 mike 1.23 const String& commandLineOptionName = String(),
424 const String& optionHelpMessage = String());
425
426 Option(const Option& x);
427
428 virtual ~Option();
429
430 Option& operator=(const Option& x);
431
432 /** Accessor */
433 const String& getOptionName() const
434 {
435 return _optionName;
436 }
437
438 /** Modifier */
439 void setOptionName(const String& optionName)
440 {
441 _optionName = optionName;
442 }
443
444 mike 1.23 /** Accessor */
445 const String& getDefaultValue() const
446 {
447 return _defaultValue;
448 }
449
450 /** Modifier. */
451 void setDefaultValue(const String& defaultValue)
452 {
453 _defaultValue = defaultValue;
454 }
455
456 /** Accessor
457 @return - Returns string representation of value
458 */
459 const String& getValue() const
460 {
461 return _value;
462 }
463
464 /** Modifier */
465 mike 1.23 void setValue(const String& value)
466 {
467 _value = value;
468 _resolved = true;
469 }
470
471 /** Accessor */
472 Boolean getRequired() const
473 {
474 return _required;
475 }
476
477 /** Modifier */
478 void setRequired(Boolean required)
479 {
480 _required = required;
481 }
482
483 /** Accessor */
484 Type getType() const
485 {
486 mike 1.23 return _type;
487 }
488
489 /** Modifier */
490 void setType(Type type)
491 {
492 _type = type;
493 }
494
495 /** Accessor */
496 const Array<String>& getDomain() const;
497
498 /** Modifier */
499 void setDomain(const Array<String>& domain);
500
501 /** Accessor */
502 const String& getCommandLineOptionName() const
503 {
504 return _commandLineOptionName;
505 }
506
507 mike 1.23 /** Accessor */
508 const String& getOptionHelpMessage() const
509 {
510 return _optionHelpMessage;
511 }
512
513 /** Modifier */
514 void setCommandLineOptionName(const String& commandLineOptionName)
515 {
516 _commandLineOptionName = commandLineOptionName;
517 }
518
519 /** Accesor. Returns true if an option value was ever obtained for
520 this option.
521 */
522 Boolean isResolved() const
523 {
524 return _resolved;
525 }
526
527 /** Checks to see if the given value is valid or not. This method may be
528 mike 1.23 overriden by derived classes to do special purpose validation of the
529 value. This implementation just checks the domain and type.
530 */
531 virtual Boolean isValid(const String& value) const;
532
533 private:
534 String _optionName;
535 String _defaultValue;
536 String _value;
537 Boolean _required;
538 Type _type;
539 Array<String> _domain;
540 String _commandLineOptionName;
541 String _optionHelpMessage;
542 Boolean _resolved;
543 };
544
545 ///////////////////////////////////////////////////////////////////////
546 // OptionRow
547 ///////////////////////////////////////////////////////////////////'//
548
549 mike 1.23 /** The OptionRow provides a declarative way of defining Option objects.
550 For the declarative programming enthusiast, we provide this structure.
551 It provides a declarative way of defining options for the OptionManager
552 class. Some developers prefer this since it makes all the options visible
553 in a kind of table like structure. Here is an example of how it can be
554 used to define a port number and hostname options. We also show how to
555 register one of these option lists with an OptionManager.
556
557 <pre>
558 static OptionRow options[] =
559 {
560 { "port", "80", false, Option::NATURAL_NUMBER },
561 { "hostname", "", true, Option::STRING }
562 };
563
564 ...
565
566 OptionManager om;
567 om.registerOptions(options, sizeof(options) / sizeof(options[0]));
568 </pre>
569
570 mike 1.23 Recall that static memory areas are initialized with zeros so that the
571 members that are not initialized explicitly in the example above are
572 initialized implicitly with zeros (which the OptionManager used to
573 determine that they are not used).
574
575 It is possible to specify domains as well. For example, suppose we
576 want to define a "color" option that can be in the following set:
577 {"red", "green", "blue"}. Here is how to express that:
578
579 <pre>
580 static const char* colors[] = { "red", "green", "blue" };
581 static const Uint32 NUM_COLORS = sizeof(colors) / sizeof(colors[0]);
582
583 static OptionRow options[] =
584 {
585 { "color", "red", false, Option::STRING, colors, NUM_COLORS }
586 };
587 </pre>
588 When a domain is defined, any of the keywords in that domain are legal
589 option keywords. For example. With the domain defined above, a command
590 line or config file entry that includes -c blue sets the option "color" to
591 mike 1.23 blue. Note that this requires a space between -c and blue.
592 */
593 struct OptionRow
594 {
595 const char* optionName;
596 const char* defaultValue;
597 int required;
598 Option::Type type;
599 char** domain;
600 Uint32 domainSize;
601 const char* commandLineOptionName;
602 const char* optionHelpMessage;
603 };
604 /* NOTE: The "required" object must be an int rather than a Boolean because
605 bool on some platforms is not defined so that we cannot use a Boolean here
606 with a static object.
607 */
608
609 /** Exception class */
|
610 karl 1.27 class OMMissingCommandLineOptionArgument : public Exception
|
611 mike 1.23 {
612 public:
613
|
614 karl 1.27 OMMissingCommandLineOptionArgument(const String& optionName)
|
615 mike 1.23 : Exception("Missing command line option argument: " + optionName) { }
616 };
617
618 /** Exception class */
|
619 karl 1.27 class OMInvalidOptionValue : public Exception
|
620 mike 1.23 {
621 public:
622
|
623 karl 1.27 OMInvalidOptionValue(const String& name, const String& value)
|
624 mike 1.23 : Exception("Invalid option value: " + name + "=\"" + value + "\"") { }
625 };
626
627 /** Exception class */
|
628 karl 1.27 class OMDuplicateOption : public Exception
|
629 mike 1.23 {
630 public:
631
|
632 karl 1.27 OMDuplicateOption(const String& name)
|
633 mike 1.23 : Exception("Duplicate option: " + name) { }
634 };
635
636 /** Exception class */
|
637 karl 1.27 class OMConfigFileSyntaxError : public Exception
|
638 mike 1.23 {
639 public:
640
|
641 karl 1.27 OMConfigFileSyntaxError(const String& file, Uint32 line)
|
642 mike 1.23 : Exception(_formatMessage(file, line)) { }
643
644 static String _formatMessage(const String& file, Uint32 line);
645 };
646
647 /** Exception class */
|
648 karl 1.27 class OMUnrecognizedConfigFileOption : public Exception
|
649 mike 1.23 {
650 public:
651
|
652 karl 1.27 OMUnrecognizedConfigFileOption(const String& name)
|
653 mike 1.23 : Exception("Unrecognized config file option: " + name) { }
654 };
655
656 /** Exception class */
|
657 karl 1.27 class OMMissingRequiredOptionValue : public Exception
|
658 mike 1.23 {
659 public:
660
|
661 karl 1.27 OMMissingRequiredOptionValue(const String& name)
|
662 mike 1.23 : Exception("Missing required option value: " + name) { }
663 };
664
|
665 karl 1.27 /** Exception class */
666 class OMMBadCmdLineOption : public Exception
667 {
668 public:
669
670 OMMBadCmdLineOption(const String& name)
671 : Exception("Parameter not Valid: " + name) { }
672 };
673
674
|
675 mike 1.23 PEGASUS_NAMESPACE_END
676
|
677 karl 1.27 #endif /* Pegasus_OM_h */
|