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