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