1 #ifndef CORELIB___NCBIARGS__HPP
2 #define CORELIB___NCBIARGS__HPP
3 
4 /*  $Id: ncbiargs.hpp 634787 2021-07-19 18:54:04Z ivanov $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author:  Denis Vakatov, Andrei Gourianov
30  *
31  *
32  */
33 
34 /// @file ncbiargs.hpp
35 /// Defines command line argument related classes.
36 ///
37 /// The CArgDescriptions and CArgDesc classes are used for describing
38 /// unparsed arguments; CArgs and CArgValue for parsed argument values;
39 /// CArgException and CArgHelpException for argument exceptions; and CArgAllow,
40 /// CArgAllow_{Strings, ..., Integers, Doubles} for argument constraints.
41 ///
42 /// The following description is included as applies to several classes in
43 /// this file:
44 ///
45 /// Parsing and validation of command-line arguments are done according to
46 /// user-provided descriptions. The command line has the following syntax:
47 ///
48 /// Command string:
49 ///
50 ///    progname  {arg_key, arg_key_opt, arg_key_dflt, arg_flag} [--]
51 ///              {arg_pos} {arg_pos_opt, arg_pos_dflt}
52 ///              {arg_extra} {arg_extra_opt}
53 ///
54 /// where:
55 ///
56 ///   arg_key        :=  -<key> <value>    -- (mandatory)
57 ///   arg_key_opt    := [-<key> <value>]   -- (optional, without default value)
58 ///   arg_key_dflt   := [-<key> <value>]   -- (optional, with default value)
59 ///   arg_flag       := -<flag>            -- (always optional)
60 ///   "--" is an optional delimiter to indicate the beginning of pos. args
61 ///   arg_pos        := <value>            -- (mandatory)
62 ///   arg_pos_opt    := [<value>]          -- (optional, without default value)
63 ///   arg_pos_dflt   := [<value>]          -- (optional, with default value)
64 ///   arg_extra      := <value>            -- (dep. on the constraint policy)
65 ///   arg_extra_opt  := [<value>]          -- (dep. on the constraint policy)
66 ///
67 /// and:
68 ///
69 ///   <key> must be followed by <value>
70 ///   <flag> and <key> are case-sensitive, and they can contain
71 ///                    only alphanumeric characters
72 ///   <value> is an arbitrary string (additional constraints can
73 ///           be applied in the argument description, see "EType")
74 ///
75 /// {arg_pos***} and {arg_extra***} -- position-dependent arguments, with
76 /// no tag preceding them.
77 /// {arg_pos***} -- have individual names and descriptions (see methods
78 /// AddPositional***).
79 /// {arg_extra***} have one description for all (see method AddExtra).
80 /// User can apply constraints on the number of mandatory and optional
81 /// {arg_extra***} arguments.
82 
83 
84 #include <corelib/ncbiobj.hpp>
85 #include <corelib/ncbi_limits.h>
86 #include <corelib/ncbitime.hpp>
87 #include <corelib/ncbimisc.hpp>
88 #include <memory>
89 #include <set>
90 #include <list>
91 #include <vector>
92 
93 
94 /** @addtogroup Args
95  *
96  * @{
97  */
98 
99 
100 BEGIN_NCBI_SCOPE
101 
102 
103 // Some necessary forward declarations.
104 class CNcbiArguments;
105 class CArgAllow;
106 class CDir;
107 class CArgDependencyGroup;
108 
109 
110 /////////////////////////////////////////////////////////////////////////////
111 ///
112 /// CArgException --
113 ///
114 /// Define exceptions class for incorrectly formed arguments.
115 ///
116 /// CArgException inherits its basic functionality from CCoreException
117 /// and defines additional error codes for malformed arguments.
118 
119 class NCBI_XNCBI_EXPORT CArgException : public CCoreException
120 {
121 public:
122     /// Error types for improperly formatted arguments.
123     ///
124     /// These error conditions are checked for and caught when processing
125     /// arguments.
126     enum EErrCode {
127         eInvalidArg,    ///< Invalid argument
128         eNoValue,       ///< Expecting an argument value
129         eExcludedValue, ///< The value is excluded by another argument
130         eWrongCast,     ///< Incorrect cast for an argument
131         eConvert,       ///< Conversion problem
132         eNoFile,        ///< Expecting a file
133         eConstraint,    ///< Argument value outside constraints
134         eArgType,       ///< Wrong argument type
135         eNoArg,         ///< No argument
136         eSynopsis       ///< Synopsis error
137     };
138 
139     /// Translate from the error code value to its string representation.
140     virtual const char* GetErrCodeString(void) const override;
141 
142     // Standard exception bolier plate code.
143     NCBI_EXCEPTION_DEFAULT(CArgException, CCoreException);
144 };
145 
146 
147 
148 /////////////////////////////////////////////////////////////////////////////
149 ///
150 /// CArgHelpException --
151 ///
152 /// Define exception class that gets thrown for Help messages.
153 ///
154 /// CArgException inherits its basic functionality from CArgException
155 /// and defines an additional error code for help.
156 
157 class NCBI_XNCBI_EXPORT CArgHelpException : public CArgException
158 {
159 public:
160     /// Error type for help exception.
161     enum EErrCode {
162         eHelp,          ///< Error code for short help message
163         eHelpFull,      ///< Error code for detailed help message
164         eHelpXml,       ///< Error code for XML formatted help message
165         eHelpErr        ///< Show short help message and return error
166     };
167 
168     /// Translate from the error code value to its string representation.
169     virtual const char* GetErrCodeString(void) const override;
170 
171     // Standard exception bolier plate code.
172     NCBI_EXCEPTION_DEFAULT(CArgHelpException, CArgException);
173 };
174 
175 
176 /////////////////////////////////////////////////////////////////////////////
177 ///
178 /// CArgValue --
179 ///
180 /// Generic abstract base class for argument values.
181 
182 class NCBI_XNCBI_EXPORT CArgValue : public CObject
183 {
184 public:
185     /// Get argument name.
GetName(void) const186     const string& GetName(void) const { return m_Name; }
187 
188     /// Check if argument holds a value.
189     ///
190     /// Argument does not hold value if it was described as optional argument
191     /// without default value, and if it was not passed a value in the command
192     /// line.  On attempt to retrieve the value from such "no-value" argument,
193     /// exception will be thrown.
194     virtual bool HasValue(void) const = 0;
195 
196     DECLARE_OPERATOR_BOOL(HasValue());
197 
198     /// Get the argument's string value.
199     ///
200     /// If it is a value of a flag argument, then return either "true"
201     /// or "false".
202     /// @sa
203     ///   AsInteger(), AsInt8(), AsDouble(), AsBoolean()
204     virtual const string& AsString(void) const = 0;
205 
206     /// Get the argument's integer (8-byte long) value.
207     ///
208     /// If you request a wrong value type, such as a call to "AsInt8()"
209     /// for a "boolean" argument, an exception is thrown.
210     /// This will however work okay for "plain integer" argument.
211     /// @sa
212     ///   AsInteger(), AsString(), AsDouble, AsBoolean()
213     virtual Int8 AsInt8(void) const = 0;
214 
215     /// Get the argument's integer value.
216     ///
217     /// If you request a wrong value type, such as a call to "AsInteger()"
218     /// for a "boolean" or even "Int8" argument, an exception is thrown.
219     /// @sa
220     ///   AsInt8(), AsString(), AsDouble, AsBoolean()
221     virtual int    AsInteger(void) const = 0;
222 
223     /// Get the argument's value as an integer id (TIntId). The actual value is
224     /// Int4 or Int8 depending on the NCBI_INT8_GI definition.
225     ///
226     /// If you request a wrong value type, such as a call to "AsIntId()"
227     /// for a "boolean", an exception is thrown. Calling AsIntId() on an
228     /// integer argument is always allowed. For an Int8 argument it will
229     /// throw an exception if NCBI_INT8_GI is not defined.
230     /// @sa
231     ///   AsInteger(), AsInt8()
232     virtual TIntId AsIntId(void) const = 0;
233 
234     /// Get the argument's double value.
235     ///
236     /// If you request a wrong value type, such as a call to "AsDouble()"
237     /// for a "boolean" argument, an exception is thrown.
238     /// @sa
239     ///   AsString(), AsInt8(), AsInteger, AsBoolean()
240     virtual double AsDouble (void) const = 0;
241 
242     /// Get the argument's boolean value.
243     ///
244     /// If you request a wrong value type, such as a call to "AsBoolean()"
245     /// for a "integer" argument, an exception is thrown.
246     /// @sa
247     ///   AsString(), AsInt8(), AsInteger, AsDouble()
248     virtual bool   AsBoolean(void) const = 0;
249 
250     enum EFileFlags {
251         fBinary   = (1 <<  1),  ///< Open file in binary mode.
252         fText     =  0,         ///< Open file in text mode.
253         fAppend   = (1 <<  2),  ///< Open file in append mode.
254         fTruncate = (1 << 12),  ///< Open file in truncate mode.
255         fNoCreate = (1 << 11),  ///< Open existing file, never create it
256         fCreatePath = (1 << 8)  ///< If needed, create directory where the file is located
257     };
258     typedef unsigned int TFileFlags;   ///< Bitwise OR of "EFileFlags"
259 
260     /// Get the argument as an input file stream.
261     virtual CNcbiIstream& AsInputFile (TFileFlags flags = 0) const = 0;
262 
263     /// Get the argument as an output file stream.
264     virtual CNcbiOstream& AsOutputFile(TFileFlags flags = 0) const = 0;
265 
266     /// Get the argument as a file stream.
267     virtual CNcbiIostream& AsIOFile(TFileFlags flags = 0) const = 0;
268 
269     /// Get the argument as a directory.
270     virtual const CDir& AsDirectory(void) const = 0;
271 
272     /// Get the argument as a DateTime.
273     virtual const CTime& AsDateTime(void) const = 0;
274 
275     /// Close the file.
276     virtual void CloseFile (void) const = 0;
277 
278     /// Some values types can contain several value lists
279     ///
280     /// Example: CGIs pass list selections by repeating the same name
281     typedef vector<string>  TStringArray;
282 
283     /// Get the value list
284     virtual const TStringArray& GetStringList() const;
285 
286     /// Get reference on value list for further modification
287     virtual TStringArray& SetStringList();
288 
289     /// Get ordinal position of the value.
290     /// NOTE: this is not the position in command line, rather
291     /// this reflects the order in which values were added to the list.
GetOrdinalPosition(void) const292     size_t GetOrdinalPosition(void) const
293     {
294         return m_Ordinal;
295     }
296 
297     /// Whether the argument:
298     /// @sa GetDefault()
299     enum EArgValueFlags {
300         fArgValue_HasDefault  = (1 << 0),  ///< Has default value
301         fArgValue_FromDefault = (1 << 1)   ///< Not provided in command line
302     };
303     typedef unsigned int TArgValueFlags;  ///< Bitwise OR of "EArgValueFlags"
304 
305     /// Get default value of the argument.
306     ///
307     /// @param flags
308     ///   Indicate whether the argument has default value, and if the arg's
309     ///   value was set from the command line or from the default value.
310     /// @return
311     ///   Default value, if specified for this argument.
312     ///   If the argument doesn't have a default value: empty string.
313     ///   If the argument is a flag: "false" or "true".
314     const string& GetDefault(TArgValueFlags* flags = NULL) const;
315 
316 protected:
317     friend class CArgs;
318     friend class CArgDescDefault;
319     friend class CArgDescMandatory;
320     friend class CArgDesc_Flag;
321 
322     /// Protected constructor and destructor.
323     ///
324     /// Prohibit explicit instantiation of CArgValue with name.
325     CArgValue(const string& name);
326     virtual ~CArgValue(void);
327 
SetOrdinalPosition(size_t pos)328     void SetOrdinalPosition(size_t pos)
329     {
330         m_Ordinal = pos;
331     }
332     void x_SetDefault(const string& def_value, bool from_def);
333 
334     string m_Name;          ///< Argument name
335     size_t m_Ordinal;
336     string m_Default;
337     TArgValueFlags m_Flags;
338 };
339 
340 
341 //  Overload the comparison operator -- to handle "CRef<CArgValue>" elements
342 //  in "CArgs::m_Args" stored as "set< CRef<CArgValue> >"
343 //
operator <(const CRef<CArgValue> & x,const CRef<CArgValue> & y)344 inline bool operator< (const CRef<CArgValue>& x, const CRef<CArgValue>& y)
345 {
346     return x->GetName() < y->GetName();
347 }
348 
349 
350 
351 /////////////////////////////////////////////////////////////////////////////
352 ///
353 /// CArgs --
354 ///
355 /// Defines parsed arguments.
356 ///
357 /// Argument values are obtained from the unprocessed command-line arguments
358 /// (via CNcbiArguments) and then verified and processed according to the
359 /// argument descriptions defined by user in "CArgDescriptions".
360 ///
361 /// NOTE:  the extra arguments can be accessed using virtual names:
362 ///           "#1", "#2", "#3", ..., "#<GetNExtra()>"
363 ///        in the order of insertion (by method Add).
364 ///
365 
366 class NCBI_XNCBI_EXPORT CArgs
367 {
368 public:
369     /// Constructor.
370     CArgs(void);
371 
372     /// Destructor.
373     ~CArgs(void);
374 
375     /// Creating copy of this object usually makes no sense
376     /// if it is really required, please use Assign method
377     NCBI_DEPRECATED_CTOR(CArgs(const CArgs& other));
378 
379     /// Creating copy of this object usually makes no sense
380     /// if it is really required, please use Assign method
381     NCBI_DEPRECATED CArgs& operator=(const CArgs& other);
382 
383     /// Copy contents of another object into this one
384     CArgs& Assign(const CArgs& other);
385 
386     /// Check existence of argument description.
387     ///
388     /// Return TRUE if arg "name" was described in the parent CArgDescriptions.
389     bool Exist(const string& name) const;
390 
391     /// Get value of argument by name. If the name starts with '-'
392     /// (e.g. '-arg') the argument can also be found by 'arg' name if there
393     /// is no another argument named 'arg'.
394     ///
395     /// Throw an exception if such argument does not exist (not described
396     /// in the CArgDescriptions).
397     ///
398     /// @attention  CArgValue::operator bool() can return TRUE even if the
399     ///             argument was not specified in the command-line -- if the
400     ///             argument has a default value.
401     /// @sa
402     ///   Exist() above.
403     const CArgValue& operator[] (const string& name) const;
404 
405     /// Get the number of unnamed positional (a.k.a. extra) args.
GetNExtra(void) const406     size_t GetNExtra(void) const { return m_nExtra; }
407 
408     /// Return N-th extra arg value,  N = 1 to GetNExtra().
409     const CArgValue& operator[] (size_t idx) const;
410 
411     /// Get all available arguments
412     vector< CRef<CArgValue> > GetAll(void) const;
413 
414     /// Print (append) all arguments to the string "str" and return "str".
415     string& Print(string& str) const;
416 
417     /// Add new argument name and value.
418     ///
419     /// Throw an exception if the "name" is not an empty string, and if
420     /// there is an argument with this name already and "update" parameter is
421     /// not set.
422     ///
423     /// HINT: Use empty "name" to add extra (unnamed) args, and they will be
424     /// automagically assigned with the virtual names: "#1", "#2", "#3", etc.
425     ///
426     /// @param arg
427     ///    argument value added to the collection
428     /// @param update
429     ///    when TRUE and argument already exists it will be replaced
430     ///    when FALSE throws an exception
431     /// @param add_value
432     ///    when TRUE and argument already exists the value is
433     ///    added to the string list (multiple argument)
434     void Add(CArgValue* arg,
435              bool       update    = false,
436              bool       add_value = false);
437 
438     /// Check if there are no arguments in this container.
439     bool IsEmpty(void) const;
440 
441     /// Remove argument of name "name"
442     void Remove(const string& name);
443 
444     /// Remove all arguments
445     void Reset(void);
446 
447     /// Get current command
448     /// @sa CCommandArgDescriptions
GetCommand(void) const449     string GetCommand(void) const
450     {
451         return m_Command;
452     }
453 
454 protected:
455     /// Set current command
456     /// @sa CCommandArgDescriptions
SetCommand(const string & command)457     CArgs* SetCommand(const string& command)
458     {
459         m_Command = command;
460         return this;
461     }
462 
463 private:
464     typedef set< CRef<CArgValue> >  TArgs;   ///< Type for arguments
465     typedef TArgs::iterator         TArgsI;  ///< Type for iterator
466     typedef TArgs::const_iterator   TArgsCI; ///< Type for const iterator
467 
468     TArgs  m_Args;    ///< Assoc. map of arguments' name/value
469     size_t m_nExtra;  ///< Cached # of unnamed positional arguments
470     string m_Command;
471 
472     /// Find argument value with name "name".
473     TArgsCI x_Find(const string& name) const;
474     TArgsI  x_Find(const string& name);
475     friend class CCommandArgDescriptions;
476 };
477 
478 
479 
480 class CArgDesc;
481 
482 
483 /////////////////////////////////////////////////////////////////////////////
484 ///
485 /// CArgErrorHandler --
486 ///
487 /// Base/default error handler for arguments parsing.
488 
489 class NCBI_XNCBI_EXPORT CArgErrorHandler : public CObject
490 {
491 public:
492     /// Process invalid argument value. The base implementation returns NULL
493     /// or throws exception depending on the CArgDesc flags.
494     /// @param arg_desc
495     ///   CArgDesc object which failed to initialize.
496     /// @param value
497     ///   String value which caused the error.
498     /// @return
499     ///   Return new CArgValue object or NULL if the argument should be
500     ///   ignored (as if it has not been set in the command line).
501     virtual CArgValue* HandleError(const CArgDesc& arg_desc,
502                                    const string& value) const;
503 };
504 
505 
506 
507 /////////////////////////////////////////////////////////////////////////////
508 ///
509 /// CArgDescriptions --
510 ///
511 /// Description of unparsed arguments.
512 ///
513 /// Container to store the command-line argument descriptions. Provides the
514 /// means for the parsing and verification of command-line arguments against
515 /// the contained descriptions.
516 ///
517 /// Example: Translating "CNcbiArguments" ---> "CArgs".
518 /// Can also be used to compose and print out the USAGE info.
519 ///
520 /// @sa CInputStreamSource
521 ///   CInputStreamSource helper class makes it possible to supply a list of
522 ///   input files, or list of directories
523 
524 class NCBI_XNCBI_EXPORT CArgDescriptions
525 {
526 public:
527     /// Constructor.
528     ///
529     /// If "auto_help" is passed TRUE, then a special flag "-h" will be added
530     /// to the list of accepted arguments. Passing "-h" in the command line
531     /// will printout USAGE and ignore all other passed arguments.
532     /// Error handler is used to process errors when parsing arguments.
533     /// If not set the default handler is used.
534     CArgDescriptions(bool auto_help = true,
535                      CArgErrorHandler* err_handler = 0);
536 
537     /// Destructor.
538     virtual ~CArgDescriptions(void);
539 
540     /// Type of CArgDescriptions
541     /// For a CGI application positional arguments and flags does not make
542     /// sense (this syntax cannot be expressed by CGI protocol)
543     enum EArgSetType {
544         eRegularArgs,  ///< Regular application
545         eCgiArgs       ///< CGI application
546     };
547 
548     /// Set type of argument description (cmdline vs CGI).
549     /// Method performs verification of arguments,
550     /// throws an exception if it finds positional args set for a CGI
551     void SetArgsType(EArgSetType args_type);
552 
GetArgsType() const553     EArgSetType GetArgsType() const { return m_ArgsType; }
554 
555     /// Processing of positional arguments.
556     /// In strict mode any value starting with '-' is treated as a key/flag
557     /// unless any positional arguments have already been found (e.g. after
558     /// '--' argument). In loose mode any argument is treated as positional
559     /// if it can not be processed as a valid key or flag.
560     enum EArgPositionalMode {
561         ePositionalMode_Strict,  ///< Strict mode (default)
562         ePositionalMode_Loose    ///< Loose mode
563     };
564 
565     /// Select mode for processing positional arguments.
SetPositionalMode(EArgPositionalMode positional_mode)566     void SetPositionalMode(EArgPositionalMode positional_mode)
567         { m_PositionalMode = positional_mode; }
568 
GetPositionalMode() const569     EArgPositionalMode GetPositionalMode() const { return m_PositionalMode; }
570 
571     /// Available argument types.
572     enum EType {
573         eString = 0, ///< An arbitrary string
574         eBoolean,    ///< {'true', 't', 'false', 'f'},  case-insensitive
575         eInt8,       ///< Convertible into an integer number (Int8 only)
576         eInteger,    ///< Convertible into an integer number (int or Int8)
577         eIntId,      ///< Convertible to TIntId (int or Int8 depending on NCBI_INT8_GI)
578         eDouble,     ///< Convertible into a floating point number (double)
579         eInputFile,  ///< Name of file (must exist and be readable)
580         eOutputFile, ///< Name of file (must be writable)
581         eIOFile,     ///< Name of file (must be writable)
582         eDirectory,  ///< Name of file directory
583         eDataSize,   ///< Integer number with possible "software" qualifiers (KB, KiB, et al)
584         eDateTime,   ///< DateTime string, formats:
585                      ///< "M/D/Y h:m:s", "Y-M-DTh:m:g", "Y/M/D h:m:g", "Y-M-D h:m:g".
586                      ///< Time string can have trailing 'Z' symbol, specifying that
587                      ///< it represent time in the UTC format.
588         k_EType_Size ///< For internal use only
589     };
590 
591     /// Get argument type's name.
592     static const char* GetTypeName(EType type);
593 
594     /// Additional flags, the first group is file related flags.
595     ///
596     /// Must match the argument type, or an exception will be thrown.
597     /// ( File related are for eInputFile and eOutputFiler argument types.)
598     enum EFlags {
599         // File related flags:
600 
601         /// Open file right away; for eInputFile, eOutputFile, eIOFile
602         fPreOpen = (1 << 0),
603         /// Open as binary file; for eInputFile, eOutputFile, eIOFile
604         fBinary  = (1 << 1),
605         /// Append to end-of-file; for eOutputFile or eIOFile
606         fAppend    = (1 << 2),
607         /// Delete contents of an existing file; for eOutputFile or eIOFile
608         fTruncate  = (1 << 12),
609         /// If the file does not exist, do not create it; for eOutputFile or eIOFile
610         fNoCreate = (1 << 11),
611         /// If needed, create directory where the file is located
612         fCreatePath = (1 << 8),
613 
614         /// Mask for all file-related flags
615         fFileFlags = fPreOpen | fBinary | fAppend | fTruncate | fNoCreate | fCreatePath,
616         // multiple keys flag:
617 
618         /// Repeated key arguments are legal (use with AddKey)
619         fAllowMultiple = (1 << 3),
620 
621         // Error handling flags:
622 
623         /// Ignore invalid argument values. If not set, exceptions will be
624         /// thrown on invalid values.
625         fIgnoreInvalidValue = (1 << 4),
626         /// Post warning when an invalid value is ignored (no effect
627         /// if fIgnoreInvalidValue is not set).
628         fWarnOnInvalidValue = (1 << 5),
629 
630         /// Allow to ignore separator between the argument's name and value.
631         /// Usual ' ' or '=' separators can still be used with the argument.
632         /// The following restrictions apply to a no-separator argument:
633         ///   - the argument must be a key (including optional or default);
634         ///   - the argument's name must be a single char;
635         ///   - no other argument's name can start with the same char,
636         ///     unless fOptionalSeparatorAllowConflict is also specified.
637         fOptionalSeparator = (1 << 6),
638         /// For arguments with fOptionalSeparator flag, allow
639         /// other arguments which names begin with the same char.
640         fOptionalSeparatorAllowConflict = (1 << 9),
641 
642         /// Require '=' separator
643         fMandatorySeparator = (1 << 7),
644 
645         /// Hide it in Usage
646         fHidden = (1 << 10),
647 
648         /// Confidential argument
649         /// Such arguments can be read from command line, from file, or from
650         /// console.
651         /// On command line, they can appear in one of the following forms:
652         ///   -key                 -- read value from console, with automatically
653         ///                           generated prompt
654         ///   -key-file fname      -- read value from file 'fname',
655         ///                           if 'fname' equals '-',  read value from
656         ///                           standard input (stdin) without any prompt
657         ///   -key-verbatim value  -- read value from the command line, as is
658         fConfidential  = (1 << 13)
659     };
660     typedef unsigned int TFlags;  ///< Bitwise OR of "EFlags"
661 
662     /// Add description for mandatory key.
663     ///
664     /// Mandatory key has the syntax:
665     ///
666     ///   arg_key := -<key> <value>
667     ///
668     /// Will throw exception CArgException if:
669     ///  - description with name "name" already exists
670     ///  - "name" contains symbols other than {alnum, '-', '_'}
671     ///  - "name" starts with more than one '-'
672     ///  - "synopsis" contains symbols other than {alnum, '_'}
673     ///  - "flags" are inconsistent with "type"
674     ///
675     /// Any argument can be later referenced using its unique name "name".
676     void AddKey(const string& name,       ///< Name of argument key
677                 const string& synopsis,   ///< Synopsis for argument
678                 const string& comment,    ///< Argument description
679                 EType         type,       ///< Argument type
680                 TFlags        flags = 0   ///< Optional flags
681                );
682 
683     /// Add description for optional key without default value.
684     ///
685     /// Optional key without default value has the following syntax:
686     ///
687     ///   arg_key_opt := [-<key> <value>]
688     ///
689     /// Will throw exception CArgException if:
690     ///  - description with name "name" already exists
691     ///  - "name" contains symbols other than {alnum, '-', '_'}
692     ///  - "name" starts with more than one '-'
693     ///  - "synopsis" contains symbols other than {alnum, '_'}
694     ///  - "flags" are inconsistent with "type"
695     ///
696     /// Any argument can be later referenced using its unique name "name".
697     void AddOptionalKey(const string& name,     ///< Name of argument key
698                         const string& synopsis, ///< Synopsis for argument
699                         const string& comment,  ///< Argument description
700                         EType         type,     ///< Argument type
701                         TFlags        flags = 0 ///< Optional flags
702                        );
703 
704     /// Add description for optional key with default value.
705     ///
706     /// Optional key with default value has the following syntax:
707     ///
708     ///   arg_key_dflt := [-<key> <value>]
709     ///
710     /// Will throw exception CArgException if:
711     ///  - description with name "name" already exists
712     ///  - "name" contains symbols other than {alnum, '-', '_'}
713     ///  - "name" starts with more than one '-'
714     ///  - "synopsis" contains symbols other than {alnum, '_'}
715     ///  - "flags" are inconsistent with "type"
716     ///
717     /// Any argument can be later referenced using its unique name "name".
718     void AddDefaultKey(const string& name,          ///< Name of argument key
719                        const string& synopsis,      ///< Synopsis for argument
720                        const string& comment,       ///< Argument description
721                        EType         type,          ///< Argument type
722                        const string& default_value, ///< Default value
723                        TFlags        flags = 0,     ///< Optional flags
724                        /// Optional name of environment variable that
725                        /// contains default value
726                        const string& env_var = kEmptyStr,
727                        /// Default value shown in Usage
728                        const char*   display_value = nullptr
729                       );
730 
731     /// Define how flag presence affect CArgValue::HasValue().
732     /// @sa AddFlag
733     enum EFlagValue {
734         eFlagHasValueIfMissed = 0,
735         eFlagHasValueIfSet    = 1
736     };
737 
738     /// Add description for flag argument.
739     ///
740     /// Flag argument has the following syntax:
741     ///
742     ///  arg_flag  := -<flag>,     <flag> := "name"
743     ///
744     /// If argument "set_value" is eFlagHasValueIfSet (TRUE), then:
745     ///    - if the flag is provided (in the command-line), then the resultant
746     ///      CArgValue::HasValue() will be TRUE;
747     ///    - else it will be FALSE.
748     ///
749     /// Setting argument "set_value" to FALSE will reverse the above meaning.
750     ///
751     /// NOTE: If CArgValue::HasValue() is TRUE, then AsBoolean() is
752     /// always TRUE.
753     void AddFlag(const string& name,      ///< Name of argument
754                  const string& comment,   ///< Argument description
755                  CBoolEnum<EFlagValue> set_value = eFlagHasValueIfSet,
756                  TFlags        flags = 0 ///< Optional flags
757                  );
758 
759     /// Add description of mandatory opening positional argument.
760     ///
761     /// Mandatory opening argument has the following syntax:
762     ///   arg_pos := <value>
763     ///
764     /// NOTE:
765     ///   In command line, mandatory opening arguments must go first,
766     ///   before any other arguments; their order is defined by the order
767     ///   in which they were described and added into CArgDescriptions.
768     ///
769     /// Will throw exception CArgException if:
770     ///  - description with name "name" already exists
771     ///  - "name" contains symbols other than {alnum, '-', '_'}
772     ///  - "name" starts with more than one '-'
773     ///  - "flags" are inconsistent with "type"
774     ///
775     /// Any argument can be later referenced using its unique name "name".
776     void AddOpening(const string& name,     ///< Name of argument
777                     const string& comment,  ///< Argument description
778                     EType         type,     ///< Argument type
779                     TFlags        flags = 0 ///< Optional flags
780                     );
781 
782     /// Add description for mandatory positional argument.
783     ///
784     /// Mandatory positional argument has the following syntax:
785     ///
786     ///   arg_pos := <value>
787     ///
788     /// NOTE: For all types of positional arguments:
789     /// - The order is important! That is, the N-th positional argument passed
790     ///   in the cmd.-line will be matched against (and processed according to)
791     ///   the N-th added named positional argument description.
792     /// - Mandatory positional args always go first.
793     ///
794     /// Will throw exception CArgException if:
795     ///  - description with name "name" already exists
796     ///  - "name" contains symbols other than {alnum, '-', '_'}
797     ///  - "name" starts with more than one '-'
798     ///  - "flags" are inconsistent with "type"
799     ///
800     /// Any argument can be later referenced using its unique name "name".
801     void AddPositional(const string& name,     ///< Name of argument
802                        const string& comment,  ///< Argument description
803                        EType         type,     ///< Argument type
804                        TFlags        flags = 0 ///< Optional flags
805                       );
806 
807     /// Add description for optional positional argument without default
808     /// value.
809     ///
810     /// Optional positional argument, without default value has the following
811     /// syntax:
812     ///
813     ///  arg_pos_opt := [<value>]
814     ///
815     /// Will throw exception CArgException if:
816     ///  - description with name "name" already exists
817     ///  - "name" contains symbols other than {alnum, '-', '_'}
818     ///  - "name" starts with more than one '-'
819     ///  - "flags" are inconsistent with "type"
820     ///
821     /// Any argument can be later referenced using its unique name "name".
822     /// @sa
823     ///   NOTE for AddPositional()
824     void AddOptionalPositional(const string& name,     ///< Name of argument
825                                const string& comment,  ///< Argument descr.
826                                EType         type,     ///< Argument type
827                                TFlags        flags = 0 ///< Optional flags
828                               );
829 
830     /// Add description for optional positional argument with default value.
831     ///
832     /// Optional positional argument with default value has the following
833     /// syntax:
834     ///
835     ///  arg_pos_dflt := [<value>]
836     ///
837     /// Will throw exception CArgException if:
838     ///  - description with name "name" already exists
839     ///  - "name" contains symbols other than {alnum, '-', '_'}
840     ///  - "name" starts with more than one '-'
841     ///  - "flags" are inconsistent with "type"
842     ///
843     /// @sa
844     ///   NOTE for AddPositional()
845     void AddDefaultPositional(const string& name,   ///< Name of argument
846                               const string& comment,///< Argument description
847                               EType         type,   ///< Argument type
848                               const string& default_value, ///< Default value
849                               TFlags        flags = 0, ///< Optional flags
850                               /// Optional name of environment variable that
851                               /// contains default value
852                               const string& env_var = kEmptyStr,
853                               /// Default value shown in Usage
854                               const char*   display_value = nullptr
855                              );
856 
857     /// Add description for the extra, unnamed positional arguments.
858     ///
859     /// The name of this description is always an empty string.
860     /// Names of the resulting arg.values will be:  "#1", "#2", ...
861     /// By default, no extra args are allowed.
862     ///
863     /// To allow an unlimited # of optional argumens pass
864     /// "n_optional" = kMax_UInt.
865     ///
866     /// Will throw exception CArgException if:
867     ///  - description with name "name" already exists
868     ///  - "flags" are inconsistent with "type"
869     void AddExtra(unsigned      n_mandatory, ///< Number of mandatory args
870                   unsigned      n_optional,  ///< Number of optional args
871                   const string& comment,     ///< Argument description
872                   EType         type,        ///< Argument type
873                   TFlags        flags = 0    ///< Optional flags
874                  );
875 
876     /// Add argument alias. The alias can be used in the command line instead
877     /// of the original argument. Accessing argument value by its alias is
878     /// not allowed (will be reported as an unknown argument). The alias will
879     /// be printed in USAGE after the original argument name.
880     /// @param alias
881     ///    New alias for a real argument.
882     /// @param arg_name
883     ///    The real argument's name.
884     void AddAlias(const string& alias, const string& arg_name);
885     /// Add negated alias for a flag argument. Using the alias in the
886     /// command line produces the same effect as using the original
887     /// flag with the opposite value. If 'arg_name' does not describe
888     /// a flag argument, an exception is thrown.
889     /// @sa
890     ///   AddAlias()
891     void AddNegatedFlagAlias(const string& alias,
892                              const string& arg_name,
893                              const string& comment = kEmptyStr);
894 
895     /// Add a dependency group.
896     /// The argument constraints specified by the dependency group(s)
897     /// will be processed only after all regular dependencies for arguments and
898     /// dependency groups have been processed.
899     /// @attention
900     ///  The "dep_group" will be added by reference, and its lifetime will then
901     ///  be managed according to the usual CObject/CRef rules.
902     /// @sa SetDependency()
903     void AddDependencyGroup(CArgDependencyGroup* dep_group);
904 
905     /// Flag to invert constraint logically
906     enum EConstraintNegate {
907         eConstraintInvert,  ///< Logical NOT
908         eConstraint         ///< Constraint is not inverted (taken as is)
909     };
910 
911     /// Set additional user defined constraint on argument value.
912     ///
913     /// Constraint is defined by CArgAllow and its derived classes.
914     /// The constraint object must be allocated by "new", and it must NOT be
915     /// freed by "delete" after it has been passed to CArgDescriptions!
916     ///
917     /// @param name
918     ///    Name of the parameter(flag) to check
919     /// @param constraint
920     ///    The constraint object.
921     ///    NOTE: A CRef will always be taken on the object, and its lifetime
922     ///    will be controlled by the CObject's smart-pointer mechanism.
923     /// @param negate
924     ///    Flag indicates if this is inverted(NOT) constaint
925     ///
926     /// @sa
927     ///   See "CArgAllow_***" classes for some pre-defined constraints
928     void SetConstraint(const string&      name,
929                        const CArgAllow*   constraint,
930                        EConstraintNegate  negate = eConstraint);
931 
932     /// This version of SetConstraint doesn't take the ownership of object
933     /// 'constraint'. Rather, it creates and uses a clone of the object.
934     void SetConstraint(const string&      name,
935                        const CArgAllow&   constraint,
936                        EConstraintNegate  negate = eConstraint);
937 
938     /// Dependencies between arguments.
939     enum EDependency {
940         eRequires, ///< One argument requires another
941         eExcludes  ///< One argument excludes another
942     };
943 
944     /// Define a dependency. If arg1 was specified and requires arg2,
945     /// arg2 is treated as a mandatory one even if was defined as optional.
946     /// If arg1 excludes arg2, arg2 must not be set even if it's mandatory.
947     /// This allows to create a set of arguments exactly one of which
948     /// must be set.
949     void SetDependency(const string& arg1,
950                        EDependency   dep,
951                        const string& arg2);
952 
953     /// Set current arguments group name. When printing descriptions for
954     /// optional arguments (on -help command), they will be arranged by
955     /// group name. Empty group name resets the group. Arguments without
956     /// group are listed first immediately after mandatory arguments.
957     void SetCurrentGroup(const string& group);
958 
959     /// Set individual error handler for the argument.
960     /// The handler overrides the default one (if any) provided through
961     /// the constructor. The same handler may be shared by several arguments.
962     /// The handler object must be allocated by "new", and it must NOT be
963     /// freed by "delete" after it has been passed to CArgDescriptions!
964     ///
965     /// @param name
966     ///    Name of the parameter (flag) to set handler for
967     /// @param err_handler
968     ///    Error handler
969     void SetErrorHandler(const string&      name,
970                          CArgErrorHandler*  err_handler);
971 
972     /// Check if there is already an argument description with specified name.
973     bool Exist(const string& name) const;
974 
975     /// Delete description of argument with name "name".
976     /// Extra arguments get deleted by the name passed as "".
977     ///
978     /// Throw the CArgException (eSynopsis error code) exception if the
979     /// specified name cannot be found.
980     void Delete(const string& name);
981 
982     /// Set extra info to be used by PrintUsage().
983     /// If "usage_name" is empty, it will be initialized using
984     /// CNcbiApplicationAPI::GetProgramDisplayName
985     /// @sa SetDetailedDescription
986     void SetUsageContext(const string& usage_name,           ///< Program name
987                          const string& usage_description,    ///< Usage descr.
988                          bool          usage_sort_args = false,///< Sort args.
989                          SIZE_TYPE     usage_width = 78);    ///< Format width
990 
991     /// Set detailed usage description
992     ///
993     /// In short help message, program will print short
994     /// description defined in SetUsageContext method.
995     /// In detailed help message, program will use detailed
996     /// description defined here.
997     ///
998     /// @param usage_description
999     ///    Detailed usage description
1000     /// @sa SetUsageContext
1001     void SetDetailedDescription( const string& usage_description);
1002 
1003     /// Print usage and exit.
1004     ///
1005     /// Force to print USAGE unconditionally (and then exit) if no
1006     /// command-line args are present.
1007     /// @deprecated Use SetMiscFlags(fUsageIfNoArgs) instead.
1008     NCBI_DEPRECATED void PrintUsageIfNoArgs(bool do_print = true);
1009 
1010     /// Miscellaneous flags.
1011     enum EMiscFlags {
1012         fNoUsage        = 1 << 0,  ///< Do not print USAGE on argument error.
1013         fUsageIfNoArgs  = 1 << 1,  ///< Force printing USAGE (and then exit)
1014                                    ///< if no command line args are present.
1015         fUsageSortArgs  = 1 << 2,  ///< Sort args when printing USAGE.
1016         fDupErrToCerr   = 1 << 3,  ///< Print arg error to both log and cerr.
1017 
1018         fMisc_Default   = 0
1019     };
1020     typedef int TMiscFlags;  ///< Bitwise OR of "EMiscFlags"
1021 
1022     /// Set the selected flags.
SetMiscFlags(TMiscFlags flags)1023     void SetMiscFlags(TMiscFlags flags)
1024     {
1025         m_MiscFlags |= flags;
1026     }
1027 
1028     /// Clear the selected usage flags.
ResetMiscFlags(TMiscFlags flags)1029     void ResetMiscFlags(TMiscFlags flags)
1030     {
1031         m_MiscFlags &= ~flags;
1032     }
1033 
1034     /// Check if the flag is set.
IsSetMiscFlag(EMiscFlags flag) const1035     bool IsSetMiscFlag(EMiscFlags flag) const
1036     {
1037         return (m_MiscFlags & flag) != 0;
1038     }
1039 
1040     /// Print usage message to end of specified string.
1041     ///
1042     /// Printout USAGE and append to the string "str" using  provided
1043     /// argument descriptions and usage context.
1044     /// @return
1045     ///   Appended "str"
1046     virtual string& PrintUsage(string& str, bool detailed = false) const;
1047 
1048     /// Print argument description in XML format
1049     ///
1050     /// @param out
1051     ///   Print into this output stream
1052     virtual void PrintUsageXml(CNcbiOstream& out) const;
1053 
1054     /// Verify if argument "name" is spelled correctly.
1055     ///
1056     /// Argument name can contain only alphanumeric characters, dashes ('-')
1057     /// and underscore ('_'), or be empty. If the leading dash is present,
1058     /// it must be followed by a non-dash char ('-' or '--foo' are not valid
1059     /// names).
1060     static bool VerifyName(const string& name, bool extended = false);
1061 
1062     /// See if special flag "-h" is activated
IsAutoHelpEnabled(void) const1063     bool IsAutoHelpEnabled(void) const
1064     {
1065         return m_AutoHelp;
1066     }
1067 
1068 private:
1069     typedef set< AutoPtr<CArgDesc> >  TArgs;    ///< Argument descr. type
1070     typedef TArgs::iterator           TArgsI;   ///< Arguments iterator
1071     typedef TArgs::const_iterator     TArgsCI;  ///< Const arguments iterator
1072     typedef /*deque*/vector<string>   TPosArgs; ///< Positional arg. vector
1073     typedef list<string>              TKeyFlagArgs; ///< List of flag arguments
1074     typedef vector<string>            TArgGroups;   ///< Argument groups
1075 
1076     // Dependencies
1077     struct SArgDependency
1078     {
SArgDependencyCArgDescriptions::SArgDependency1079         SArgDependency(const string arg, EDependency dep)
1080             : m_Arg(arg), m_Dep(dep) {}
1081         string      m_Arg;
1082         EDependency m_Dep;
1083     };
1084     // Map arguments to their dependencies
1085     typedef multimap<string, SArgDependency> TDependencies;
1086     typedef TDependencies::const_iterator TDependency_CI;
1087 
1088 private:
1089     EArgSetType  m_ArgsType;     ///< Type of arguments
1090     TArgs        m_Args;         ///< Assoc.map of arguments' name/descr
1091     TPosArgs     m_PosArgs;      ///< Pos. args, ordered by position in cmd.-line
1092     TPosArgs     m_OpeningArgs;  ///< Opening args, ordered by position in cmd.-line
1093     TKeyFlagArgs m_KeyFlagArgs;  ///< Key/flag args, in order of insertion
1094     string       m_NoSeparator;  ///< Arguments allowed to use no separator
1095     unsigned     m_nExtra;       ///> # of mandatory extra args
1096     unsigned     m_nExtraOpt;    ///< # of optional  extra args
1097     TArgGroups   m_ArgGroups;    ///< Argument groups
1098     size_t       m_CurrentGroup; ///< Currently selected group (0 = no group)
1099     EArgPositionalMode m_PositionalMode; ///< Processing of positional args
1100     TDependencies      m_Dependencies;   ///< Arguments' dependencies
1101     TMiscFlags   m_MiscFlags;    ///< Flags for USAGE, error handling etc.
1102     set< CConstRef<CArgDependencyGroup> > m_DependencyGroups;
1103 
1104     // Extra USAGE info
1105 protected:
1106     string    m_UsageName;         ///< Program name
1107     string    m_UsageDescription;  ///< Program description
1108     string    m_DetailedDescription;  ///< Program long description
1109     SIZE_TYPE m_UsageWidth;        ///< Maximum length of a usage line
1110     bool      m_AutoHelp;          ///< Special flag "-h" activated
1111     friend class CCommandArgDescriptions;
1112 
1113 private:
1114 
1115     CRef<CArgErrorHandler> m_ErrorHandler; ///< Global error handler or NULL
1116 
1117     // Internal methods
1118 
1119     void x_PrintAliasesAsXml(CNcbiOstream& out, const string& name,
1120                                                 bool negated=false) const;
1121 
1122     /// Helper method to find named parameter.
1123     /// 'negative' (if provided) will indicate if the name referred to a
1124     /// negative alias.
1125     TArgsI  x_Find(const string& name,
1126                    bool*         negative = NULL);
1127 
1128     /// Helper method to find named parameter -- const version.
1129     /// 'negative' (if provided) will indicate if the name referred to a
1130     /// negative alias.
1131     TArgsCI x_Find(const string& name,
1132                    bool*         negative = NULL) const;
1133 
1134     /// Get group index. Returns group index in the m_ArgGroups, 0 for empty
1135     /// group name or the next group number for undefined group.
1136     size_t x_GetGroupIndex(const string& group) const;
1137 
1138     /// Helper method for adding description.
1139     void x_AddDesc(CArgDesc& arg);
1140 
1141     /// Helper method for doing pre-processing consistency checks.
1142     void x_PreCheck(void) const;
1143 
1144     void x_PrintComment(list<string>&   arr,
1145                         const CArgDesc& arg,
1146                         SIZE_TYPE       width) const;
1147 
1148     /// Process arguments.
1149     ///
1150     /// Helper method to process arguments and build a CArgs object that is
1151     /// passed as the args parameter.
1152     /// @return
1153     ///   TRUE if specified "arg2" was used.
1154     bool    x_CreateArg(const string& arg1, ///< Argument to process
1155                         bool have_arg2, ///< Is there an arg. that follows?
1156                         const string& arg2, ///< Following argument
1157                         unsigned* n_plain,  ///< Indicates number of args
1158                         CArgs& args         ///< Contains processed args
1159                        ) const;
1160 
1161     /// @return
1162     ///   TRUE if specified "arg2" was used.
1163     bool x_CreateArg(const string& arg1,
1164                      const string& name,
1165                      bool          have_arg2,
1166                      const string& arg2,
1167                      unsigned int  n_plain,
1168                      CArgs&        args,
1169                      bool          update = false,
1170                      CArgValue**   new_value = 0) const;
1171 
1172     /// @sa x_PostCheck()
1173     enum EPostCheckCaller {
1174         eCreateArgs,  ///< called by CreateArgs()
1175         eConvertKeys  ///< called by ConvertKeys()
1176     };
1177     /// Helper method for doing post-processing consistency checks.
1178     void x_PostCheck(CArgs&           args,
1179                      unsigned int     n_plain,
1180                      EPostCheckCaller caller)
1181         const;
1182 
1183     /// Returns TRUE if parameter supports multiple arguments
1184     bool x_IsMultiArg(const string& name) const;
1185 
1186 protected:
1187 
1188     /// Helper method for checking if auto help requested and throw
1189     /// CArgHelpException if help requested.
1190     void x_CheckAutoHelp(const string& arg) const;
1191 
1192 // PrintUsage helpers
1193     class CPrintUsage
1194     {
1195     public:
1196         CPrintUsage(const CArgDescriptions& desc);
1197         ~CPrintUsage();
1198         void AddSynopsis(list<string>& arr, const string& intro, const string& prefix) const;
1199         void AddDescription(list<string>& arr, bool detailed) const;
1200         void AddCommandDescription(list<string>& arr, const string& cmd,
1201             const map<string,string>* aliases, size_t max_cmd_len, bool detailed) const;
1202         void AddDetails(list<string>& arr) const;
1203     private:
1204         const CArgDescriptions& m_desc;
1205         list<const CArgDesc*> m_args;
1206     };
1207     class CPrintUsageXml
1208     {
1209     public:
1210         CPrintUsageXml(const CArgDescriptions& desc, CNcbiOstream& out);
1211         ~CPrintUsageXml();
1212         void PrintArguments(const CArgDescriptions& desc) const;
1213     private:
1214         const CArgDescriptions& m_desc;
1215         CNcbiOstream& m_out;
1216     };
1217 
1218 public:
1219     /// Create parsed arguments in CArgs object.
1220     ///
1221     /// Parse command-line arguments, and create "CArgs" args object
1222     /// from the passed command-line arguments "argc" and "argv".
1223     ///
1224     /// Throw
1225     ///  - CArgException on error
1226     ///  - CArgHelpException if USAGE printout was requested ("-h" flag)
1227     ///
1228     /// @note Deallocate the resulting "CArgs" object using 'delete'.
1229     ///
1230     /// @attention
1231     ///  This function is not suitable for parsing URL-encoded _CGI_ arg
1232     ///  outside of the CCgiApplication framework.
1233     template<class TSize, class TArray>
CreateArgs(TSize argc,TArray argv) const1234     CArgs* CreateArgs(TSize argc, TArray argv) const
1235     {
1236         // Check the consistency of argument descriptions
1237         x_PreCheck();
1238 
1239         // Create new "CArgs" to fill up, and parse cmd.-line args into it
1240         unique_ptr<CArgs> args(new CArgs());
1241 
1242         // Special case for CGI -- a lone positional argument
1243         if (GetArgsType() == eCgiArgs  &&  argc == 2) {
1244             x_CheckAutoHelp(argv[1]);
1245             return args.release();
1246         }
1247 
1248         // Regular case for both CGI and non-CGI
1249         unsigned int n_plain = kMax_UInt;
1250         for (TSize i = 1;  i < argc;  i++) {
1251             bool have_arg2 = (i + 1 < argc);
1252             if ( x_CreateArg(argv[i], have_arg2,
1253                              have_arg2 ? (string) argv[i+1] : kEmptyStr,
1254                              &n_plain, *args) ) {
1255                 i++;
1256             }
1257         }
1258 
1259         // Check if there were any arguments at all
1260         if (n_plain == kMax_UInt) {
1261             n_plain = 0;
1262         }
1263 
1264         // Extra checks for the consistency of resultant argument values
1265         x_PostCheck(*args, n_plain, eCreateArgs);
1266         return args.release();
1267     }
1268 
1269     /// Parse command-line arguments 'argv' out of CNcbiArguments
1270     virtual CArgs* CreateArgs(const CNcbiArguments& argv) const;
1271 
1272     /// Convert argument map (key-value pairs) into arguments in accordance
1273     /// with the argument descriptions
1274     template<class T>
ConvertKeys(CArgs * args,const T & arg_map,bool update) const1275     void ConvertKeys(CArgs* args, const T& arg_map, bool update) const
1276     {
1277         // Check the consistency of argument descriptions
1278         x_PreCheck();
1279 
1280         // Retrieve the arguments and their values
1281         ITERATE(TKeyFlagArgs, it, m_KeyFlagArgs) {
1282             const string& param_name = *it;
1283 
1284             // find first element in the input multimap
1285             typename T::const_iterator vit  = arg_map.find(param_name);
1286             typename T::const_iterator vend = arg_map.end();
1287 
1288             if (vit != vend) {   // at least one value found
1289                 CArgValue* new_arg_value;
1290                 x_CreateArg(param_name, param_name,
1291                             true, /* value is present */
1292                             vit->second,
1293                             1,
1294                             *args,
1295                             update,
1296                             &new_arg_value);
1297 
1298                 if (new_arg_value  &&  x_IsMultiArg(param_name)) {
1299                     CArgValue::TStringArray& varr =
1300                         new_arg_value->SetStringList();
1301 
1302                     // try to add all additional arguments to arg value
1303                     for (++vit;  vit != vend;  ++vit) {
1304                         if (vit->first != param_name)
1305                             break;
1306                         varr.push_back(vit->second);
1307                     }
1308                 }
1309             }
1310         } // ITERATE
1311 
1312         // Extra checks for the consistency of resultant argument values
1313         x_PostCheck(*args, 0, eConvertKeys);
1314     }
1315 
GetAllDescriptions(void)1316     virtual list<CArgDescriptions*> GetAllDescriptions(void) {
1317         return list<CArgDescriptions*>({this});
1318     }
1319 };
1320 
1321 /////////////////////////////////////////////////////////////////////////////
1322 ///
1323 /// CCommandArgDescriptions --
1324 ///
1325 /// Container for several CArgDescriptions objects.
1326 ///
1327 /// Sometimes, it is convenient to use a command line tool as follows:
1328 ///    tool <command> [options] [args]
1329 /// Here, <command> is an alphanumeric string,
1330 /// and options and arguments are different for each command.
1331 /// With this mechanism, it is possible to describe arguments for
1332 /// each command separately. At run time, argument parser will choose
1333 /// proper CArgDescriptions object based on the value of the first argument.
1334 
1335 class NCBI_XNCBI_EXPORT CCommandArgDescriptions : public CArgDescriptions
1336 {
1337 public:
1338 
1339     enum ECommandArgFlags {
1340         eCommandMandatory = 0,      ///< Nonempty command is required
1341         eCommandOptional  = 1,      ///< Command is not necessary
1342         eNoSortCommands   = (1<<1), ///< On PrintUsage, keep commands unsorted
1343         eNoSortGroups     = (1<<2)  ///< On PrintUsage, keep command groups unsorted
1344     };
1345     typedef unsigned int TCommandArgFlags;   ///< Bitwise OR of ECommandArgFlags
1346 
1347     /// Constructor.
1348     ///
1349     /// If "auto_help" is passed TRUE, then a special flag "-h" will be added
1350     /// to the list of accepted arguments. Passing "-h" in the command line
1351     /// will printout USAGE and ignore all other passed arguments.
1352     /// Error handler is used to process errors when parsing arguments.
1353     /// If not set the default handler is used.
1354     CCommandArgDescriptions(bool auto_help = true,
1355                           CArgErrorHandler* err_handler = 0,
1356                           TCommandArgFlags cmd_flags = eCommandMandatory);
1357     /// Destructor.
1358     virtual ~CCommandArgDescriptions(void);
1359 
1360     /// Set current command group name. When printing help,
1361     /// commands will be arranged by group name.
1362     void SetCurrentCommandGroup(const string& group);
1363 
1364     enum ECommandFlags {
1365         eDefault = 0,
1366         eHidden  = 1   ///<  Hide command in Usage
1367     };
1368 
1369     /// Add command argument descriptions
1370     ///
1371     /// @param cmd
1372     ///    Command string
1373     /// @param description
1374     ///    Argument description
1375     /// @param alias
1376     ///    Alternative name of the command
1377     /// @param flags
1378     ///    Optional flags
1379     void AddCommand(const string& cmd, CArgDescriptions* description,
1380                     const string& alias = kEmptyStr, ECommandFlags flags = eDefault);
1381 
1382     /// Parse command-line arguments 'argv'
1383     virtual CArgs* CreateArgs(const CNcbiArguments& argv) const;
1384 
1385     /// Print usage message to end of specified string.
1386     ///
1387     /// Printout USAGE and append to the string "str" using  provided
1388     /// argument descriptions and usage context.
1389     /// @return
1390     ///   Appended "str"
1391     virtual string& PrintUsage(string& str, bool detailed = false) const;
1392 
1393     /// Print argument description in XML format
1394     ///
1395     /// @param out
1396     ///   Print into this output stream
1397     virtual void PrintUsageXml(CNcbiOstream& out) const;
1398 
1399     virtual list<CArgDescriptions*> GetAllDescriptions(void);
1400 
1401 private:
1402     // not allowed
SetArgsType(EArgSetType)1403     void SetArgsType(EArgSetType /*args_type*/) { }
1404 
1405     bool x_IsCommandMandatory(void) const;
1406     size_t x_GetCommandGroupIndex(const string& group) const;
1407     string x_IdentifyCommand(const string& command) const;
1408 
1409     typedef map<string, AutoPtr<CArgDescriptions> > TDescriptions;
1410     TCommandArgFlags m_Cmd_req;
1411     TDescriptions m_Description;    ///< command to ArgDescriptions
1412     map<string, size_t > m_Groups;  ///< command to group #
1413     map<string,string> m_Aliases;   ///< command to alias; one alias only
1414     list<string> m_Commands;        ///< command names, and order
1415     list<string> m_CmdGroups;       ///< group names, and order
1416     size_t m_CurrentCmdGroup;       ///< current group #
1417     mutable string m_Command;       ///< current command
1418 };
1419 
1420 
1421 
1422 /////////////////////////////////////////////////////////////////////////////
1423 ///
1424 /// CArgAllow --
1425 ///
1426 /// Abstract base class for defining argument constraints.
1427 ///
1428 /// Other user defined constraints are defined by deriving from this abstract
1429 /// base class:
1430 ///
1431 ///  - CArgAllow_Symbols  -- symbol from a set of allowed symbols
1432 ///  - CArgAllow_String   -- string to contain only allowed symbols
1433 ///  - CArgAllow_Strings  -- string from a set of allowed strings
1434 ///  - CArgAllow_Int8s    -- Int8    value to fall within a given interval
1435 ///  - CArgAllow_Integers -- integer value to fall within a given interval
1436 ///  - CArgAllow_Doubles  -- floating-point value to fall in a given interval
1437 ///
1438 /// @sa CArgAllow_Regexp
1439 
1440 class NCBI_XNCBI_EXPORT CArgAllow : public CObject
1441 {
1442 public:
1443     /// Verify if specified value is allowed.
1444     virtual bool Verify(const string &value) const = 0;
1445 
1446     /// Get usage information.
1447     virtual
1448     string GetUsage(void) const = 0;
1449 
1450     /// Print constraints in XML format
1451     virtual void PrintUsageXml(CNcbiOstream& out) const;
1452 
1453     virtual ~CArgAllow(void);
1454 
1455     /// Create object's clone, moving it from stack memory into heap.
1456     /// The method is required only when using objects created on stack.
1457     ///
1458     /// NOTE: Default implementation returns NULL.
1459     /// Inherited classes must override this method.
1460     ///
1461     /// @sa CArgDescriptions::SetConstraint
1462     virtual CArgAllow* Clone(void) const;
1463 
1464 protected:
1465     // In the absence of the following constructor, new compilers (as required
1466     // by the new C++ standard) may fill the object memory with zeros,
1467     // erasing flags set by CObject::operator new (see CXX-1808)
CArgAllow(void)1468     CArgAllow(void) {}
1469 };
1470 
1471 
1472 
1473 /////////////////////////////////////////////////////////////////////////////
1474 ///
1475 /// CArgAllow_Symbols --
1476 ///
1477 /// Define constraint to describe exactly one symbol.
1478 ///
1479 /// Argument to be exactly one symbol from the specified set of symbols.
1480 ///
1481 /// Examples:
1482 /// - To allow only symbols 'a', 'b' and 'Z' for argument "MyArg":
1483 ///   SetConstraint("MyArg", new CArgAllow_Symbols("abZ"))
1484 /// - To allow only printable symbols (according to "isprint()" from <ctype.h>):
1485 ///   SetConstraint("MyArg", new CArgAllow_Symbols(CArgAllow_Symbols::ePrint))
1486 
1487 class NCBI_XNCBI_EXPORT CArgAllow_Symbols : public CArgAllow
1488 {
1489 public:
1490     /// Symbol class for defining sets of characters.
1491     ///
1492     /// Symbol character classes patterned after those defined in <ctype.h>.
1493     enum ESymbolClass {
1494         // Standard character class from <ctype.h>:  isalpha(), isdigit(), etc.
1495         eAlnum,  ///< Alphanumeric characters
1496         eAlpha,  ///< Alphabet characters
1497         eCntrl,  ///< Control characters
1498         eDigit,  ///< Digit characters
1499         eGraph,  ///< Graphical characters
1500         eLower,  ///< Lowercase characters
1501         ePrint,  ///< Printable characters
1502         ePunct,  ///< Punctuation characters
1503         eSpace,  ///< Space characters
1504         eUpper,  ///< Uppercase characters
1505         eXdigit, ///< Hexadecimal characters
1506         eUser    ///< User defined characters using constructor with string&
1507     };
1508 
1509     /// Constructor.
1510     CArgAllow_Symbols(ESymbolClass symbol_class);
1511 
1512     /// Constructor for user defined eUser class.
1513     CArgAllow_Symbols(const string& symbol_set);
1514 
1515     /// Add allowed symbols
1516     CArgAllow_Symbols& Allow(ESymbolClass  symbol_class);
1517     CArgAllow_Symbols& Allow(const string& symbol_set);
1518 
1519 protected:
1520     /// Verify if specified value is allowed.
1521     virtual bool Verify(const string& value) const;
1522 
1523     /// Get usage information.
1524     virtual string GetUsage(void) const;
1525 
1526     /// Print constraints in XML format
1527     virtual void PrintUsageXml(CNcbiOstream& out) const;
1528 
CArgAllow_Symbols(void)1529     CArgAllow_Symbols(void) {
1530     }
1531     virtual CArgAllow* Clone(void) const;
1532 
1533     typedef pair<ESymbolClass, string> TSymClass;
1534     set< TSymClass > m_SymClass;
1535 };
1536 
1537 
1538 /////////////////////////////////////////////////////////////////////////////
1539 ///
1540 /// CArgAllow_String --
1541 ///
1542 /// Define constraint to describe string argument.
1543 ///
1544 /// Argument to be a string containing only allowed symbols.
1545 ///
1546 /// Examples:
1547 /// - To allow string containing only symbols 'a', 'b' and 'Z' for arg MyArg:
1548 ///   SetConstraint("MyArg", new CArgAllow_String("abZ"))
1549 /// - To allow only numeric symbols (according to "isdigit()" from <ctype.h>):
1550 ///   SetConstraint("MyArg", new CArgAllow_String(CArgAllow_String::eDigit))
1551 
1552 class NCBI_XNCBI_EXPORT CArgAllow_String : public CArgAllow_Symbols
1553 {
1554 public:
1555     /// Constructor.
1556     CArgAllow_String(ESymbolClass symbol_class);
1557 
1558     /// Constructor for user defined eUser class.
1559     CArgAllow_String(const string& symbol_set);
1560 
1561 protected:
1562     /// Verify if specified value is allowed.
1563     virtual bool Verify(const string& value) const;
1564 
1565     /// Get usage information.
1566     virtual string GetUsage(void) const;
1567 
1568     /// Print constraints in XML format
1569     virtual void PrintUsageXml(CNcbiOstream& out) const;
1570 
CArgAllow_String(void)1571     CArgAllow_String(void) {
1572     }
1573     virtual CArgAllow* Clone(void) const;
1574 };
1575 
1576 
1577 
1578 /////////////////////////////////////////////////////////////////////////////
1579 ///
1580 /// CArgAllow_Strings --
1581 ///
1582 /// Define constraint to describe set of string values.
1583 ///
1584 /// Argument to have only particular string values. Use the Allow() method to
1585 /// add the allowed string values, which can be daisy-chained.
1586 ///
1587 /// Examples:
1588 /// - SetConstraint("a", (new CArgAllow_Strings)->
1589 ///                  Allow("foo")->Allow("bar")->Allow("etc"))
1590 /// - You can use "operator,()" to shorten the notation:
1591 ///   SetConstraint("b", &(*new CArgAllow_Strings, "foo", "bar", "etc"))
1592 
1593 class NCBI_XNCBI_EXPORT CArgAllow_Strings : public CArgAllow
1594 {
1595 public:
1596     /// Constructor
1597     /// @param use_case
1598     ///   If to ignore the case of the characters
1599     CArgAllow_Strings(NStr::ECase use_case = NStr::eCase);
1600 
1601     /// Constructor
1602     /// @param values
1603     ///   Strings to add to the set of allowed string values
1604     /// @param use_case
1605     ///   If to ignore the case of the characters
1606     CArgAllow_Strings(initializer_list<string> values, NStr::ECase use_case = NStr::eCase);
1607 
1608     /// Add allowed string values
1609     /// @param value
1610     ///   String to add to the set of allowed string values
1611     CArgAllow_Strings* Allow(const string& value);
1612 
1613     /// Add allowed string values
1614     /// @param value
1615     ///   String to add to the set of allowed string values
1616     CArgAllow_Strings& AllowValue(const string& value);
1617 
1618     /// Short notation operator for adding allowed string values
1619     /// @param value
1620     ///   String to add to the set of allowed string values
1621     /// @sa
1622     ///   Allow()
operator ,(const string & value)1623     CArgAllow_Strings& operator,(const string& value) {
1624         return AllowValue(value);
1625     }
1626 
1627 protected:
1628     /// Verify if specified value is allowed.
1629     virtual bool Verify(const string& value) const;
1630 
1631     /// Get usage information.
1632     virtual string GetUsage(void) const;
1633 
1634     /// Print constraints in XML format
1635     virtual void PrintUsageXml(CNcbiOstream& out) const;
1636 
1637     virtual CArgAllow* Clone(void) const;
1638 
1639     /// Type of the container that contains the allowed string values
1640     /// @sa m_Strings
1641     typedef set<string, PNocase_Conditional> TStrings;
1642 
1643     TStrings     m_Strings;  ///< Set of allowed string values
1644 };
1645 
1646 
1647 /////////////////////////////////////////////////////////////////////////////
1648 ///
1649 /// CArgAllow_Int8s --
1650 ///
1651 /// Define constraint to describe range of 8-byte integer values and TIntIds.
1652 ///
1653 /// Argument to have only integer values falling within given interval.
1654 ///
1655 /// Example:
1656 /// - SetConstraint("a2", new CArgAllow_Int8s(-1001, 123456789012))
1657 
1658 class NCBI_XNCBI_EXPORT CArgAllow_Int8s : public CArgAllow
1659 {
1660 public:
1661     /// Constructor specifying an allowed integer value.
1662     CArgAllow_Int8s(Int8 x_value);
1663 
1664     /// Constructor specifying range of allowed integer values.
1665     CArgAllow_Int8s(Int8 x_min, Int8 x_max);
1666 
1667     /// Add allow values
1668     CArgAllow_Int8s& AllowRange(Int8 from, Int8 to);
1669     CArgAllow_Int8s& Allow(Int8 value);
1670 
1671 protected:
1672     /// Verify if specified value is allowed.
1673     virtual bool   Verify(const string& value) const;
1674 
1675     /// Get usage information.
1676     virtual string GetUsage(void) const;
1677 
1678     /// Print constraints in XML format
1679     virtual void PrintUsageXml(CNcbiOstream& out) const;
1680 
CArgAllow_Int8s(void)1681     CArgAllow_Int8s(void) {
1682     }
1683     virtual CArgAllow* Clone(void) const;
1684 
1685 
1686     typedef pair<Int8, Int8> TInterval;
1687     set< TInterval >  m_MinMax;
1688 };
1689 
1690 
1691 
1692 /////////////////////////////////////////////////////////////////////////////
1693 ///
1694 /// CArgAllow_Integers --
1695 ///
1696 /// Define constraint to describe range of integer id values.
1697 ///
1698 /// Argument to have only integer values falling within given interval.
1699 ///
1700 /// Example:
1701 /// - SetConstraint("i", new CArgAllow_Integers(kMin_Int, 34))
1702 
1703 class NCBI_XNCBI_EXPORT CArgAllow_Integers : public CArgAllow_Int8s
1704 {
1705 public:
1706     /// Constructor specifying an allowed integer value.
1707     CArgAllow_Integers(int x_value);
1708     /// Constructor specifying range of allowed integer values.
1709     CArgAllow_Integers(int x_min, int x_max);
1710 
1711 protected:
1712     /// Get usage information.
1713     virtual string GetUsage(void) const;
1714 
CArgAllow_Integers(void)1715     CArgAllow_Integers(void) {
1716     }
1717     virtual CArgAllow* Clone(void) const;
1718 };
1719 
1720 
1721 
1722 /////////////////////////////////////////////////////////////////////////////
1723 ///
1724 /// CArgAllow_Doubles --
1725 ///
1726 /// Define constraint to describe range of double values.
1727 ///
1728 /// Argument to have only double values falling within given interval.
1729 ///
1730 /// Example:
1731 /// - SetConstraint("d", new CArgAllow_Doubles(0.01, 0.99))
1732 
1733 class NCBI_XNCBI_EXPORT CArgAllow_Doubles : public CArgAllow
1734 {
1735 public:
1736     /// Constructor specifying an allowed double value.
1737     CArgAllow_Doubles(double x_value);
1738 
1739     /// Constructor specifying range of allowed double values.
1740     CArgAllow_Doubles(double x_min, double x_max);
1741 
1742     /// Add allowed values
1743     CArgAllow_Doubles& AllowRange(double from, double to);
1744     CArgAllow_Doubles& Allow(double value);
1745 
1746 protected:
1747     /// Verify if specified value is allowed.
1748     virtual bool   Verify(const string& value) const;
1749 
1750     /// Get usage information.
1751     virtual string GetUsage(void) const;
1752 
1753     /// Print constraints in XML format
1754     virtual void PrintUsageXml(CNcbiOstream& out) const;
1755 
CArgAllow_Doubles(void)1756     CArgAllow_Doubles(void) {
1757     }
1758     virtual CArgAllow* Clone(void) const;
1759 
1760     typedef pair<double,double> TInterval;
1761     set< TInterval >  m_MinMax;
1762 };
1763 
1764 
1765 
1766 /////////////////////////////////////////////////////////////////////////////
1767 ///
1768 /// CArgDesc --
1769 ///
1770 /// Base class for the description of various types of argument.
1771 ///
1772 /// This was a pre-declaration; in MSVC, a predeclaration here causes a heap
1773 /// corruption on termination because this class's virtual destructor isn't
1774 /// defined at the moment the compiler instantiates the destructor of
1775 /// AutoPtr<CArgDesc>.
1776 
1777 class NCBI_XNCBI_EXPORT CArgDesc
1778 {
1779 public:
1780     /// Constructor.
1781     CArgDesc(const string& name,     ///< Argument name
1782              const string& comment,  ///< Argument description
1783              CArgDescriptions::TFlags flags = 0
1784             );
1785 
1786     /// Destructor.
1787     virtual ~CArgDesc(void);
1788 
1789     /// Get argument name.
GetName(void) const1790     const string& GetName   (void) const { return m_Name; }
1791 
1792     /// Get argument description.
GetComment(void) const1793     const string& GetComment(void) const { return m_Comment; }
1794 
1795     /// Get argument group
GetGroup(void) const1796     virtual size_t GetGroup(void) const { return 0; }
1797     /// Set argument group
SetGroup(size_t)1798     virtual void SetGroup(size_t /* group */) {}
1799 
1800     /// Get usage synopsis.
1801     virtual string GetUsageSynopsis(bool name_only = false) const = 0;
1802 
1803     /// Get usage comment attribute.
1804     virtual string GetUsageCommentAttr(void) const = 0;
1805 
1806     /// Process argument with specified value.
1807     virtual CArgValue* ProcessArgument(const string& value) const = 0;
1808 
1809     /// Process argument default.
1810     virtual CArgValue* ProcessDefault(void) const = 0;
1811 
1812     /// Verify argument default value.
1813     virtual void VerifyDefault (void) const;
1814 
1815     /// Set argument constraint.
1816     /// @param constraint
1817     ///    The constraint object.
1818     ///    ATTN: A CRef must always be taken on the object by the
1819     ///          derived class's implementation of this method!
1820     virtual
1821     void SetConstraint(const CArgAllow*                     constraint,
1822                        CArgDescriptions::EConstraintNegate  negate
1823                                     = CArgDescriptions::eConstraint);
1824 
1825     /// Returns TRUE if associated constraint is inverted (NOT)
1826     /// @sa SetConstraint
IsConstraintInverted() const1827     virtual bool IsConstraintInverted() const { return false; }
1828 
1829     /// Get argument constraint.
1830     virtual const CArgAllow* GetConstraint(void) const;
1831 
1832     /// Get usage constraint.
1833     string GetUsageConstraint(void) const;
1834 
1835     /// Get error handler for the argument
GetErrorHandler(void) const1836     virtual const CArgErrorHandler* GetErrorHandler(void) const { return 0; }
1837     /// Set error handler for the argument
SetErrorHandler(CArgErrorHandler *)1838     virtual void SetErrorHandler(CArgErrorHandler*) { return; }
1839 
1840     /// Get argument flags
GetFlags(void) const1841     CArgDescriptions::TFlags GetFlags(void) const { return m_Flags; }
1842 
1843     /// Print description in XML format
1844     string PrintXml(CNcbiOstream& out) const;
1845 
1846 private:
1847     string m_Name;      ///< Argument name
1848     string m_Comment;   ///< Argument description
1849     CArgDescriptions::TFlags  m_Flags;
1850 };
1851 
1852 /////////////////////////////////////////////////////////////////////////////
1853 
1854 class NCBI_XNCBI_EXPORT CArgDependencyGroup : public CObject
1855 {
1856 public:
1857     /// Create new dependency group.
1858     /// @param name
1859     ///  Name of the group
1860     /// @param description
1861     ///  User-provided description of the dependency group (for Usage).
1862     ///  A generated description will be added to it.
1863     static CRef<CArgDependencyGroup> Create(
1864         const string& name, const string& description = kEmptyStr);
1865 
1866     virtual ~CArgDependencyGroup(void);
1867 
1868     /// @param min_members
1869     ///  Mark this group as "set" (in the context of
1870     ///  CArgDescriptions::EDependency) if at least "min_members" of its
1871     ///  members (args or groups listed in this group) are set.
1872     /// @note This condition can be weakened by "eInstantSet" mechanism.
1873     /// @sa EInstantSet
1874     /// @return "*this"
1875     CArgDependencyGroup& SetMinMembers(size_t min_members);
1876 
1877     /// @param max_members
1878     ///  No more than "max_members" of members (args or immediate groups
1879     ///  listed in this group) are allowed to be in the "set" state.
1880     ///  If this condition is not met, then this group will be marked
1881     ///  as "not set".
1882     /// @return "*this"
1883     CArgDependencyGroup& SetMaxMembers(size_t max_members);
1884 
1885     /// Control whether the "setting" of this particular member marks the
1886     /// whole group as "set" regardless of the value passed to  SetMinMembers()
1887     /// @sa SetMinMembers(), Add()
1888     enum EInstantSet {
1889         eNoInstantSet,
1890         eInstantSet
1891     };
1892 
1893     /// Make a regular argument a member of this dependency group.
1894     /// An argument with this name will need to be added separately using
1895     /// CArgDescriptions::AddXXX().
1896     /// @param arg_name
1897     ///  Name of the argument, as specified in CArgDescriptions::AddXXX()
1898     /// @param instant_set
1899     ///  "eInstantSet" means that if the added argument ("arg_name") is
1900     ///  set, then the SetMinMembers() condition doesn't apply anymore.
1901     /// @return  "*this"
1902     CArgDependencyGroup& Add(const string& arg_name,
1903                              EInstantSet  instant_set = eNoInstantSet);
1904 
1905     /// Make another dependency group a member of this dependency group.
1906     /// @attention
1907     ///  The "dep_group" will be added by reference, and its lifetime will
1908     ///  be managed according to the usual CObject/CRef rules.
1909     /// @param instant_set
1910     ///  "eInstantSet" means that if the added group ("dep_group") is
1911     ///  set, then the SetMinMembers() condition doesn't apply anymore.
1912     /// @return  "*this"
1913     CArgDependencyGroup& Add(CArgDependencyGroup* dep_group,
1914                              EInstantSet instant_set = eNoInstantSet);
1915 
1916 private:
1917     bool x_Evaluate( const CArgs& args, string* arg_set, string* arg_unset) const;
1918 
1919     string m_Name;
1920     string m_Description;
1921     size_t m_MinMembers, m_MaxMembers;
1922     map<string,                         EInstantSet> m_Arguments;
1923     map<CConstRef<CArgDependencyGroup>, EInstantSet> m_Groups;
1924 
1925     // prohibit unwanted ctors and assignments
1926     CArgDependencyGroup(void);
1927     CArgDependencyGroup( const CArgDependencyGroup& dep_group);
1928     CArgDependencyGroup& operator= (const CArgDependencyGroup&);
1929 
1930 public:
1931     void PrintUsage(list<string>& arr, size_t offset) const;
1932     void PrintUsageXml(CNcbiOstream& out) const;
1933     void Evaluate( const CArgs& args) const;
1934 };
1935 
1936 END_NCBI_SCOPE
1937 
1938 
1939 /* @} */
1940 
1941 #endif  /* CORELIB___NCBIARGS__HPP */
1942