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