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