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

  1 mike  1.1 //BEGIN_LICENSE
  2           //
  3           // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
  4           //
  5           // Permission is hereby granted, free of charge, to any person obtaining a
  6           // copy of this software and associated documentation files (the "Software"),
  7           // to deal in the Software without restriction, including without limitation
  8           // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9           // and/or sell copies of the Software, and to permit persons to whom the
 10           // Software is furnished to do so, subject to the following conditions:
 11           //
 12           // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 13           // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 14           // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 15           // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 16           // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 17           // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 18           // DEALINGS IN THE SOFTWARE.
 19           //
 20           //END_LICENSE
 21           //BEGIN_HISTORY
 22 mike  1.1 //
 23           // Author: Michael E. Brasher
 24           //
 25 mike  1.2 // $Log: OptionManager.h,v $
 26 mike  1.8 // Revision 1.7  2001/04/14 07:46:47  mike
 27           // new
 28           //
 29 mike  1.7 // Revision 1.6  2001/04/14 07:35:04  mike
 30           // Added config file loading to OptionManager
 31           //
 32 mike  1.6 // Revision 1.5  2001/04/14 06:41:17  mike
 33           // New
 34           //
 35 mike  1.5 // Revision 1.4  2001/04/14 03:37:16  mike
 36           // Added new example to test option manager
 37           //
 38 mike  1.4 // Revision 1.3  2001/04/14 02:26:42  mike
 39           // More on option manager implementation
 40           //
 41 mike  1.3 // Revision 1.2  2001/04/14 02:11:41  mike
 42           // New option manager class.
 43           //
 44 mike  1.2 // Revision 1.1  2001/04/14 01:52:45  mike
 45           // New option management class.
 46           //
 47 mike  1.1 //
 48           //END_HISTORY
 49           
 50           #ifndef Pegasus_OptionManager_h
 51           #define Pegasus_OptionManager_h
 52           
 53           #include <Pegasus/Common/Config.h>
 54           #include <Pegasus/Common/String.h>
 55           #include <Pegasus/Common/Array.h>
 56 mike  1.4 #include <Pegasus/Common/Exception.h>
 57 mike  1.1 
 58           PEGASUS_NAMESPACE_BEGIN
 59           
 60           class Option;
 61 mike  1.5 struct OptionRow;
 62 mike  1.1 
 63           /** The OptionManager class manages a collection of program options. 
 64           
 65               <h4>Overview</h4>
 66           
 67               A program option may be specified in one of three ways:
 68           
 69               <ul>
 70           	<li>As an environment variable</li>
 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 all three of these 
 76               sources into a single unified collection. The following example showss 
 77               how to 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 mike  1.1 
 84           	    ...
 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               Methods are also provided for merging options from files and the environment
 96               (see OptionManager::mergeFile(), OptionManager::mergeEnvironment()).
 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 mike  1.1 	<li>The default value (to be used if not specified elsewhere)</li>
105           	<li>Whether the option is required</li>
106 mike  1.2 	<li>The option's type (e.g., boolean, integer or string)</li>
107 mike  1.1 	<li>The domain of the option if any (set of legal values)</li>
108           	<li>The name the option as it appears as an environment variable</li>
109           	<li>The name the option as it appears in a configuration file</li>
110           	<li>The name the option as it appears on the command line</li>
111               </ul>
112           
113               Here is how to regsiter an option:
114           
115               <pre>
116           	OptionManager om;
117           
118 mike  1.5 	Option* option = new Option("port", "80", false, Option::NATURAL_NUMBER,
119 mike  1.2 	    Array<String>(), "PEGASUS_PORT", "PORT", "p");
120 mike  1.1 
121           	om.registerOption(option);
122               </pre>
123           
124               The arguments of the Option constructor are the same (and in the same
125 mike  1.2     order) as the list just above. Notice that option name is "port", Whereas
126               the environment variable is named "PEGASUS_PORT" and the option name
127               in the configuration file is "port" and the command line option argument
128               name is "p" (will appear as -p on the command line).
129 mike  1.1 
130               Once options have been registered, the option values may be obtained using
131               the merge methods described earlier. During merging, certain validation is
132               done using the corresponding Option instance described above.
133           
134               Once options have been merged, they may obtained by calling the 
135               lookupOption() method like this:
136               
137               <pre>
138           	Option* option = om.lookupOption("port");
139           
140           	String port = option->getValue();
141               </pre>
142           
143               <h4>Command Line Options</h4>
144           
145               To merge option values from the command line argument, call
146               mergeCommandLine() like this:
147           
148               <pre>
149           	om.mergeCommandLine(argc, argv);
150 mike  1.1     </pre>
151               
152               This method searches the command line for options that match the registered 
153               ones. It will extract those options from the command line (argc and argv 
154               will be modified accordingly).
155           
156               <h4>Configuration File Otpions</h4>
157           
158               Options from a configuration file may be merged by calling the mergeFile() 
159               method like this:
160           
161               <pre>
162           	om.mergeFile(fileName);
163               </pre>
164           
165               This searches the file for options matching registered ones. Exceptions
166               are thrown for any unrecognized option names that are encountered.
167           
168               <h4>Environment Variable Options</h4>
169           
170               The mergeEnvironment() method merges options from the enviroment space of
171 mike  1.1     the process.
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.</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 mike  1.2 
187               <h4>Typcial Usage</h4>
188           
189               The OptionManager is typically used in the following way. First, options
190               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 mike  1.1 */
195 mike  1.2 class PEGASUS_COMMON_LINKAGE OptionManager
196 mike  1.1 {
197           public:
198           
199               /** Constructor. */
200               OptionManager();
201           
202               /** Destructor. Deletes all contained Options. */
203               ~OptionManager();
204           
205               /** Registers an option. The OptionManager is responsible for disposing
206           	of the option; the caller must not delete this object.
207           
208 mike  1.8 	@param option option to be registerd.
209 mike  1.7 	@exception NullPointer exception if option argument is null.
210           	@exception DuplicateOption if option already defined.
211 mike  1.5     */
212               void registerOption(Option* option);
213           
214               /** Provides a simple way to register several options at once using
215           	a declartive style table. This may also be done programmitically
216           	by repeatedly calling registerOption above. See documentation for
217           	OptionRow for details on how to use them.
218 mike  1.1     */
219 mike  1.5     void registerOptions(OptionRow* options, Uint32 numOptions);
220 mike  1.1 
221               /** Merge option values from the command line. Searches the command 
222           	line for registered options whose names are given by the
223           	Option::getCommandLineOptionName() method. Validation is performed
224           	on each option value obtained by calling Option::isValid(). Valid
225           	option values are set by calling Option::setValue(). The argc and
226           	argv arguments are modified: the option and its argument are 
227           	stripped from the command line. The option and its argument have the
228           	following form: -option-name argument. A space must be supplied
229           	between the two. Boolean option arguments are an exception. They
230           	must have the form -option. If they are present, then they are
231           	taken to be true.
232           
233 mike  1.8 	&param argc number of argument on the command line.
234           	&param argv list of command line arguments.
235 mike  1.7 	&exception InvalidOptionValue if validation fails.
236           	&exception MissingCommandLineOptionArgument
237 mike  1.1     */
238               void mergeCommandLine(int& argc, char**& argv);
239           
240               /** Merge option values from the environment. Searches the environment
241           	for registered options whose names are given by the
242           	Option::getEnvironmentVariableName() method. Validation is performed
243           	on each option value  obtained by calling Option::isValid(). Valid
244           	option values are set by calling Option::setValue().
245           
246 mike  1.7 	&exception BadEnvironmentOption if validation fails.
247 mike  1.1     */
248               void mergeEnvironment();
249           
250               /** Merge option values from a file. Searches file for registered options
251           	whose names are given by the Option::getEnvironmentVariableName()
252           	method. Validation is performed on each option value by calling
253           	Option::isValid(). Valid option values are set by calling 
254           	Option::setValue().
255           
256 mike  1.8 	&param fileName name of file to be merged.
257 mike  1.7 	&exception NoSuchFile if file cannot be opened.
258           	&exception BadConfigFileOption
259 mike  1.1     */
260               void mergeFile(const String& fileName);
261           
262               /** After merging, this method is called to check for required options
263           	that were not merged (specified).
264           
265 mike  1.7 	&exception UnspecifiedRequiredOption
266 mike  1.1     */
267               void checkRequiredOptions() const;
268           
269 mike  1.2     /** Lookup the option with the given name.
270 mike  1.4 	@return 0 if no such option.
271 mike  1.2     */
272 mike  1.4     const Option* lookupOption(const String& name) const;
273 mike  1.3 
274 mike  1.6     /** Lookup value of an option.
275               */
276               Boolean lookupValue(const String& name, String& value) const;
277           
278 mike  1.3     /** Print all the options. */
279               void print() const;
280 mike  1.2 
281 mike  1.1 private:
282           
283 mike  1.4     /** Lookup the option by its commandLineOptionName.
284           	@return 0 if no such option.
285               */
286               Option* _lookupOptionByCommandLineOptionName(const String& name);
287           
288 mike  1.6     /** Lookup the option by its configFileOptionName.
289           	@return 0 if no such option.
290               */
291               Option* _lookupOptionByConfigFileOptionName(const String& name);
292           
293 mike  1.1     Array<Option*> _options;
294           };
295           
296           /** The Option class is used to specify information about an Option.
297           
298               See the OptionManager class for more details.
299           */
300 mike  1.2 class PEGASUS_COMMON_LINKAGE Option
301 mike  1.1 {
302           public:
303           
304               /** Valid value types. */
305 mike  1.5     enum Type 
306               {
307           	// (..., -3, -2, -1, 0, 1, 2, 3, ...)
308           	INTEGER, 
309           
310           	// (1, 2, 3, ...)
311           	NATURAL_NUMBER, 
312           
313           	// (0, 1, 2, 3, ...)
314           	WHOLE_NUMBER, 
315           
316           	// "true" or "false"
317           	BOOLEAN, 
318           
319           	// Anything
320           	STRING
321               };
322 mike  1.1 
323               // Hack to fix bug in MSVC.
324               typedef Array<String> StringArray;
325           
326               /** Constructor.
327           
328 mike  1.8 	@param optionName the name of this option.
329 mike  1.1 
330 mike  1.8 	@param defaultValue the default value of this option.
331 mike  1.1 
332 mike  1.8 	@param required whether the value of this option is required.
333 mike  1.1 
334 mike  1.8 	@param type type of the value. This is used to validate the value.
335 mike  1.1 
336 mike  1.8 	@param domain list of legal value for this option. If this list
337 mike  1.1 	    is empty, then no domain is enforced.
338           
339 mike  1.8 	@param environmentVariableName name of the corresponding environment
340 mike  1.1 	    variable (which may be different from the option name).
341           
342 mike  1.8 	@param configFileOptionName name of the corresponding variable
343 mike  1.1 	    in the config file (which may be different from the option name).
344           
345 mike  1.8 	@param commandLineOptionName name of the corresponding command line
346 mike  1.1 	    option (which may be different from the option name).
347               */
348               Option(
349                   const String& optionName,
350                   const String& defaultValue,
351                   Boolean required,
352                   Type type,
353                   const StringArray& domain = StringArray(),
354                   const String& environmentVariableName = String(),
355 mike  1.6         const String& configFileOptionName = String(),
356 mike  1.2         const String& commandLineOptionName = String());
357           
358               Option(const Option& x);
359 mike  1.1 
360               virtual ~Option();
361           
362 mike  1.2     Option& operator=(const Option& x);
363 mike  1.1 
364               /** Accessor */
365               const String& getOptionName() const
366               {
367                   return _optionName;
368               }
369           
370               /** Modifier */
371               void setOptionName(const String& optionName)
372               {
373                   _optionName = optionName;
374               }
375           
376               /** Accessor */
377               const String& getDefaultValue() const
378               {
379                   return _defaultValue;
380               }
381           
382               /** Modifier. */
383               void setDefaultValue(const String& defaultValue)
384 mike  1.1     {
385                   _defaultValue = defaultValue;
386               }
387           
388               /** Accessor */
389               const String& getValue() const
390               {
391                   return _value;
392               }
393           
394               /** Modifier */
395               void setValue(const String& value)
396               {
397                   _value = value;
398               }
399           
400               /** Accessor */
401               Boolean getRequired() const
402               {
403                   return _required;
404               }
405 mike  1.1 
406               /** Modifier */
407               void setRequired(Boolean required)
408               {
409                   _required = required;
410               }
411           
412               /** Accessor */
413               Type getType() const
414               {
415                   return _type;
416               }
417           
418               /** Modifier */
419               void setType(Type type)
420               {
421                   _type = type;
422               }
423           
424               /** Accessor */
425               const StringArray& getDomain() const
426 mike  1.1     {
427                   return _domain;
428               }
429           
430               /** Modifier */
431               void setDomain(const StringArray& domain)
432               {
433                   _domain = domain;
434               }
435           
436               /** Accessor */
437               const String& getEnvironmentVariableName() const
438               {
439                   return _environmentVariableName;
440               }
441           
442               /** Modifier */
443               void setEnvironmentVariableName(const String& environmentVariableName)
444               {
445                   _environmentVariableName = environmentVariableName;
446               }
447 mike  1.1 
448               /** Accessor */
449 mike  1.6     const String& getConfigFileOptionName() const
450 mike  1.1     {
451 mike  1.6         return _configFileOptionName;
452 mike  1.1     }
453           
454               /** Modifier */
455 mike  1.6     void setConfigFileOptionName(const String& configFileOptionName)
456 mike  1.1     {
457 mike  1.6         _configFileOptionName = configFileOptionName;
458 mike  1.1     }
459           
460               /** Accessor */
461               const String& getCommandLineOptionName() const
462               {
463                   return _commandLineOptionName;
464               }
465           
466               /** Modifier */
467               void setCommandLineOptionName(const String& commandLineOptionName)
468               {
469                   _commandLineOptionName = commandLineOptionName;
470               }
471           
472               /** Accesor. Returns true if an option value was ever obtained for 
473           	this option.
474               */
475               Boolean foundValue() const 
476               { 
477           	return _foundValue; 
478               }
479 mike  1.1 
480               /** Checks to see if the given value is valid or not. This method may be
481           	overriden by derived classes to do special purpose validation of the
482           	value. This implementation just checks the domain and type.
483               */
484               virtual Boolean isValid(const String& value) const;
485           
486           private:
487               String _optionName;
488               String _defaultValue;
489               String _value;
490               Boolean _required;
491               Type _type;
492               StringArray _domain;
493               String _environmentVariableName;
494 mike  1.6     String _configFileOptionName;
495 mike  1.1     String _commandLineOptionName;
496               Boolean _foundValue;
497 mike  1.4 };
498           
499 mike  1.5 /** The OptionRow provides a declarative way of defining Option objects.
500               For the declarative programming enthusiast, we provide this structure.
501               It provides a declarative way of defining options for the OptionManager
502               class. Some developers prefer this since it makes all the options visible
503               in a kind of table like structure. Here is an example of how it can be
504               used to define a port number and hostname options. We also show how to
505               register one of these option lists with an OptionManager.
506           
507               <pre>
508           	static OptionRow options[] =
509           	{
510           	    { "port", "80", false, Option::NATURAL_NUMBER },
511           	    { "hostname", "", true, Option::STRING }
512           	};
513           
514           	...
515           
516           	OptionManager om;
517           	om.registerOptions(options, sizeof(options) / sizeof(options[0]));
518               </pre>
519           
520 mike  1.5     Recall that static memory areas are initialized with zeros so that the
521               members that are not initialized explicitly in the example above are
522               initialized implicitly with zeros (which the OptionManager used to
523               determine that they are not used).
524           
525               It is possible to specify domains as well. For example, suppose we
526               want to define a "color" option that can be in the following set:
527               {"red", "green", "blue"}. Here is how to express that:
528           
529               <pre>
530           	static const char* colors[] = { "red", "green", "blue" };
531           
532           	static OptionRow options[] = 
533           	{
534           	    { "color", "red", false, Option::STRING, colors, 3 }
535           	};
536               </pre>
537           */
538           struct OptionRow
539           {
540               const char* optionName;
541 mike  1.5     const char* defaultValue;
542               Boolean required;
543               Option::Type type;
544               char** domain;
545               Uint32 domainSize;
546               const char* environmentVariableName;
547 mike  1.6     const char* configFileOptionName;
548 mike  1.5     const char* commandLineOptionName;
549           };
550           
551           /** Exception class */
552 mike  1.4 class MissingCommandLineOptionArgument : public Exception
553           {
554           public:
555           
556               MissingCommandLineOptionArgument(const String& optionName)
557           	: Exception("Missing command line option argument: " + optionName) { }
558           };
559           
560 mike  1.5 /** Exception class */
561           class InvalidOptionValue : public Exception
562           {
563           public:
564           
565               InvalidOptionValue(const String& name, const String& value)
566           	: Exception("Invalid option value: " + name + "=\"" + value + "\"") { }
567           };
568           
569           /** Exception class */
570           class DuplicateOption : public Exception
571 mike  1.4 {
572           public:
573           
574 mike  1.5     DuplicateOption(const String& name)
575           	: Exception("Duplicate option: " + name) { }
576 mike  1.6 };
577           
578           /** Exception class */
579           class ConfigFileSyntaxError : public Exception
580           {
581           public:
582           
583               ConfigFileSyntaxError(const String& file, Uint32 line)
584           	: Exception(_formatMessage(file, line)) { }
585           
586               static String _formatMessage(const String& file, Uint32 line);
587           };
588           
589           /** Exception class */
590           class UnrecognizedConfigFileOption : public Exception
591           {
592           public:
593           
594               UnrecognizedConfigFileOption(const String& name)
595           	: Exception("Unrecognized config file option: " + name) { }
596 mike  1.1 };
597           
598           PEGASUS_NAMESPACE_END
599           
600           #endif /* Pegasus_OptionManager_h */

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2