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

  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            
 61 mike  1.24 // REVIEW: I seem to remember seeing another class that does something like
 62            // REVIEW: this.
 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            	&param argc number of argument on the command line.
264            	&param 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            	&param 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 */

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2