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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2