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 // Modified By: Karl Schopmyer
26 //
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 mike 1.23
44 #include <Pegasus/Common/Config.h>
45 #include <Pegasus/Common/String.h>
46 #include <Pegasus/Common/Array.h>
47 #include <Pegasus/Common/Exception.h>
48
49 PEGASUS_NAMESPACE_BEGIN
50
51 class Option;
52 struct OptionRow;
53
54 PEGASUS_MEMORY_FUNCTIONS(Option*)
55
56 typedef Option* OptionPtr;
57 #define PEGASUS_ARRAY_T OptionPtr
58 # include "ArrayInter.h"
59 #undef PEGASUS_ARRAY_T
60
|
63 mike 1.23
64 /** The OptionManager class manages a collection of program options.
65
66 <h4>Overview</h4>
67
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 mike 1.23 ...
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 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 mike 1.23 <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 </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 mike 1.23
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
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 <h4>Command Line Options</h4>
147 mike 1.23
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
167 This searches the file for options matching registered ones. Exceptions
168 mike 1.23 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 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 mike 1.23 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 parameters that are represented by strings following the option
209 keyword. No limitations are placed on the string except that it must
210 mike 1.23 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 /** Constructor. */
230 OptionManager();
231 mike 1.23
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 @exception DuplicateOption if option already defined.
241 */
242 void registerOption(Option* option);
243
244 /** Provides a simple way to register several options at once using
245 a declartive style table. This may also be done programmitically
246 by repeatedly calling registerOption above. See documentation for
247 OptionRow for details on how to use them.
248 */
249 void registerOptions(OptionRow* options, Uint32 numOptions);
250
251 /** Merge option values from the command line. Searches the command
252 mike 1.23 line for registered options whose names are given by the
253 Option::getCommandLineOptionName() method. Validation is performed
254 on each option value obtained by calling Option::isValid(). Valid
255 option values are set by calling Option::setValue(). The argc and
256 argv arguments are modified: the option and its argument are
257 stripped from the command line. The option and its argument have the
258 following form: -option-name argument. A space must be supplied
259 between the two. Boolean option arguments are an exception. They
260 must have the form -option. If they are present, then they are
261 taken to be true.
262
263 ¶m argc number of argument on the command line.
264 ¶m argv list of command line arguments.
265 &exception InvalidOptionValue if validation fails.
266 &exception MissingCommandLineOptionArgument
267 */
268 void mergeCommandLine(int& argc, char**& argv);
269
270 /** Merge option values from a file. Searches file for registered options
271 whose names are given by the options which have been registered.
272 Validation is performed on each option value by calling
273 mike 1.23 Option::isValid(). Valid option values are set by calling
274 Option::setValue().
275
276 ¶m fileName name of file to be merged.
277 &exception NoSuchFile if file cannot be opened.
278 &exception BadConfigFileOption
279 */
280 void mergeFile(const String& fileName);
281
282 /** After merging, this method is called to check for required options
283 that were not merged (specified).
284
285 &exception MissingRequiredRequiredOption
286 */
287 void checkRequiredOptions() const;
288
289 /** Lookup the option with the given name.
290 @param Name provides the name of the option.
291 @return 0 if no such option.
292 */
293 const Option* lookupOption(const String& name) const;
294 mike 1.23
295 /** Lookup value of an option.
296 @param Name provides the name of the option (ex. "port")
297 @param String parameter contains the String that contains the
298 value for this parameter (in String format).
299 @return Boolean return. True if the option found.
300 */
301 Boolean lookupValue(const String& name, String& value) const;
302
303 /** isStringInOptionMask - Looks for a String value in an option.
304 This function is used to detect particular options listed in strings of
305 entries forming a STRING option. Thus, for example if the option string
306 were "abc,def,ijk" in option toy isStringInOption ("toy", "def") returns
307 true.
308 @param option name of the option in the option table
309 @param entry Entry to compare
310 @return True if the entry String is found in the option.
311 */
312 //Uint32 isStringInOptionMask (const String& option, String& entry) const;
313
314 /** optionValueEquals - Test the string value of an option.
315 mike 1.23 @param name provides the name of the option (ex. "port")
316 @param value String value for comparison.
317 @return true if the option exists and the value of the option
318 equals the input parameter value.
319 */
320 Boolean valueEquals(const String& name, const String& value) const;
321
322
323 /** Print all the options. */
324 void print() const;
325
326 /** Print the help line for all options including cmdline name, name
327 and the help string
328 */
329 void printHelp() const;
330
331
332 private:
333
334 /** Lookup the option by its commandLineOptionName.
335 @return 0 if no such option.
336 mike 1.23 */
337 Option* _lookupOptionByCommandLineOptionName(const String& name);
338
339 Array<Option*> _options;
340 };
341
342 //////////////////////////////////////////////////////////////////
343 // OPTION CLASS
344 //////////////////////////////////////////////////////////////////
345
346 /** The Option class is used to specify information about an Option.
347
348 See the OptionManager class for more details.
349 */
350 class PEGASUS_COMMON_LINKAGE Option
351 {
352 public:
353
354 /** Valid value types. */
355 enum Type
356 {
357 mike 1.23 // (..., -3, -2, -1, 0, 1, 2, 3, ...)
358 INTEGER,
359
360 // (1, 2, 3, ...)
361 NATURAL_NUMBER,
362
363 // (0, 1, 2, 3, ...)
364 WHOLE_NUMBER,
365
366 // "true" or "false"
367 BOOLEAN,
368
369 // Anything
370 STRING
371 };
372
373 /** Constructor.
374
375 @param optionName the name of this option.
376
377 @param defaultValue the default value of this option.
378 mike 1.23
379 @param required whether the value of this option is required.
380
381 @param type type of the value. This is used to validate the value.
382
383 @param domain list of legal value for this option. If this list
384 is empty, then no domain is enforced.
385
386 @param commandLineOptionName name of the corresponding command line
387 option (which may be different from the option name).
388
389 @param optionHelpMessage Text message that defines option. To be used
390 in Usage messages.
391 */
392 Option(
393 const String& optionName,
394 const String& defaultValue,
395 Boolean required,
396 Type type,
397 const Array<String>& domain = EmptyStringArray(),
398 const String& commandLineOptionName = String(),
399 mike 1.23 const String& optionHelpMessage = String());
400
401 Option(const Option& x);
402
403 virtual ~Option();
404
405 Option& operator=(const Option& x);
406
407 /** Accessor */
408 const String& getOptionName() const
409 {
410 return _optionName;
411 }
412
413 /** Modifier */
414 void setOptionName(const String& optionName)
415 {
416 _optionName = optionName;
417 }
418
419 /** Accessor */
420 mike 1.23 const String& getDefaultValue() const
421 {
422 return _defaultValue;
423 }
424
425 /** Modifier. */
426 void setDefaultValue(const String& defaultValue)
427 {
428 _defaultValue = defaultValue;
429 }
430
431 /** Accessor
432 @return - Returns string representation of value
433 */
434 const String& getValue() const
435 {
436 return _value;
437 }
438
439 /** Modifier */
440 void setValue(const String& value)
441 mike 1.23 {
442 _value = value;
443 _resolved = true;
444 }
445
446 /** Accessor */
447 Boolean getRequired() const
448 {
449 return _required;
450 }
451
452 /** Modifier */
453 void setRequired(Boolean required)
454 {
455 _required = required;
456 }
457
458 /** Accessor */
459 Type getType() const
460 {
461 return _type;
462 mike 1.23 }
463
464 /** Modifier */
465 void setType(Type type)
466 {
467 _type = type;
468 }
469
470 /** Accessor */
471 const Array<String>& getDomain() const;
472
473 /** Modifier */
474 void setDomain(const Array<String>& domain);
475
476 /** Accessor */
477 const String& getCommandLineOptionName() const
478 {
479 return _commandLineOptionName;
480 }
481
482 /** Accessor */
483 mike 1.23 const String& getOptionHelpMessage() const
484 {
485 return _optionHelpMessage;
486 }
487
488 /** Modifier */
489 void setCommandLineOptionName(const String& commandLineOptionName)
490 {
491 _commandLineOptionName = commandLineOptionName;
492 }
493
494 /** Accesor. Returns true if an option value was ever obtained for
495 this option.
496 */
497 Boolean isResolved() const
498 {
499 return _resolved;
500 }
501
502 /** Checks to see if the given value is valid or not. This method may be
503 overriden by derived classes to do special purpose validation of the
504 mike 1.23 value. This implementation just checks the domain and type.
505 */
506 virtual Boolean isValid(const String& value) const;
507
508 private:
509 String _optionName;
510 String _defaultValue;
511 String _value;
512 Boolean _required;
513 Type _type;
514 Array<String> _domain;
515 String _commandLineOptionName;
516 String _optionHelpMessage;
517 Boolean _resolved;
518 };
519
520 ///////////////////////////////////////////////////////////////////////
521 // OptionRow
522 ///////////////////////////////////////////////////////////////////'//
523
524 /** The OptionRow provides a declarative way of defining Option objects.
525 mike 1.23 For the declarative programming enthusiast, we provide this structure.
526 It provides a declarative way of defining options for the OptionManager
527 class. Some developers prefer this since it makes all the options visible
528 in a kind of table like structure. Here is an example of how it can be
529 used to define a port number and hostname options. We also show how to
530 register one of these option lists with an OptionManager.
531
532 <pre>
533 static OptionRow options[] =
534 {
535 { "port", "80", false, Option::NATURAL_NUMBER },
536 { "hostname", "", true, Option::STRING }
537 };
538
539 ...
540
541 OptionManager om;
542 om.registerOptions(options, sizeof(options) / sizeof(options[0]));
543 </pre>
544
545 Recall that static memory areas are initialized with zeros so that the
546 mike 1.23 members that are not initialized explicitly in the example above are
547 initialized implicitly with zeros (which the OptionManager used to
548 determine that they are not used).
549
550 It is possible to specify domains as well. For example, suppose we
551 want to define a "color" option that can be in the following set:
552 {"red", "green", "blue"}. Here is how to express that:
553
554 <pre>
555 static const char* colors[] = { "red", "green", "blue" };
556 static const Uint32 NUM_COLORS = sizeof(colors) / sizeof(colors[0]);
557
558 static OptionRow options[] =
559 {
560 { "color", "red", false, Option::STRING, colors, NUM_COLORS }
561 };
562 </pre>
563 When a domain is defined, any of the keywords in that domain are legal
564 option keywords. For example. With the domain defined above, a command
565 line or config file entry that includes -c blue sets the option "color" to
566 blue. Note that this requires a space between -c and blue.
567 mike 1.23 */
568 struct OptionRow
569 {
570 const char* optionName;
571 const char* defaultValue;
572 int required;
573 Option::Type type;
574 char** domain;
575 Uint32 domainSize;
576 const char* commandLineOptionName;
577 const char* optionHelpMessage;
578 };
579 /* NOTE: The "required" object must be an int rather than a Boolean because
580 bool on some platforms is not defined so that we cannot use a Boolean here
581 with a static object.
582 */
583
584 /** Exception class */
585 class MissingCommandLineOptionArgument : public Exception
586 {
587 public:
588 mike 1.23
589 MissingCommandLineOptionArgument(const String& optionName)
590 : Exception("Missing command line option argument: " + optionName) { }
591 };
592
593 /** Exception class */
594 class InvalidOptionValue : public Exception
595 {
596 public:
597
598 InvalidOptionValue(const String& name, const String& value)
599 : Exception("Invalid option value: " + name + "=\"" + value + "\"") { }
600 };
601
602 /** Exception class */
603 class DuplicateOption : public Exception
604 {
605 public:
606
607 DuplicateOption(const String& name)
608 : Exception("Duplicate option: " + name) { }
609 mike 1.23 };
610
611 /** Exception class */
612 class ConfigFileSyntaxError : public Exception
613 {
614 public:
615
616 ConfigFileSyntaxError(const String& file, Uint32 line)
617 : Exception(_formatMessage(file, line)) { }
618
619 static String _formatMessage(const String& file, Uint32 line);
620 };
621
622 /** Exception class */
623 class UnrecognizedConfigFileOption : public Exception
624 {
625 public:
626
627 UnrecognizedConfigFileOption(const String& name)
628 : Exception("Unrecognized config file option: " + name) { }
629 };
630 mike 1.23
631 /** Exception class */
632 class MissingRequiredOptionValue : public Exception
633 {
634 public:
635
636 MissingRequiredOptionValue(const String& name)
637 : Exception("Missing required option value: " + name) { }
638 };
639
640 PEGASUS_NAMESPACE_END
641
642 #endif /* Pegasus_OptionManager_h */
|