(file) Return to OptionManager.h CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2