// balcl_commandline.h -*-C++-*- #ifndef INCLUDED_BALCL_COMMANDLINE #define INCLUDED_BALCL_COMMANDLINE #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide command line parsing, validation, and access. // //@CLASSES: // balcl::CommandLine: value-semantic command-line arguments // balcl::CommandLineOptionsHandle: references to parsed options // //@SEE_ALSO: balcl_optionvalue, balcl_optiontype // //@DESCRIPTION: This component provides a value-semantic class, // 'balcl::CommandLine', used to represent the command-line arguments passed to // a process. Also provided is 'balcl::CommandLineOptionsHandle', a class that // provides access to the options (and associative values, if any) found in a // 'balcl::CommandLine' object in a "parsed" state. // // The constructor of 'balcl::CommandLine' takes a specification describing the // command-line arguments. Once created, 'printUsage' can be invoked to print // the usage syntax. The 'parse' method takes command-line arguments and // validates them against the specification supplied at construction, printing // suitable messages on an optionally-specified stream in case of a parsing // error. Once parsed, options and values can be accessed using various access // methods. The class provides a set of *theType* access methods (for example, // 'theString', 'theInt') that return the value of the specified option name. // It is also possible to link a variable with an option in the specification; // doing so will cause the variable to be loaded with the option value once // 'parse' has been invoked and was successful. The 'options' method returns a // 'balcl::CommandLineOptionsHandle' containing option names and their values. // ///Component Features Summary ///-------------------------- // This component offers the following features: // //: 1 Validation of command-line arguments against the provided specification. //: //: 2 The ability to specify sophisticated constraints easily. Users can also //: build their own constraints and use them in the specification. //: //: 3 The ability to automatically generate usage syntax. //: //: 4 The ability to directly link a variable to an option. Parsing a command //: line loads such variables with the option value as specified on the //: command line (or a default value if one is configured). Linked variables //: provide a sometimes convenient alternative to using the accessor methods. //: See {Type-and-Constraint Field}. Linked variables can be 'bsl::optional' //: objects for each of the scalar option types except 'bool'. //: //: 5 The ability to access options and their corresponding values through //: various accessor methods. //: //: 6 The ability to parse Unix-style command lines (for example, grouping of //: flags, allowing any ordering of options, or a mix between options and //: non-option arguments, short tag and long tag forms, etc.). //: //: 7 The ability to have multiple non-option arguments of possibly different //: types. Note that only the last non-option argument may be multi-valued, //: and that if a non-option has a default value, then all subsequent //: non-options must also have a default value. // // A lower bound can be placed on the number of multi-valued non-option // arguments (e.g., two or more values) can be achieved by explicitly // specifying the required number of single-valued non-option arguments of the // same type before the unrestricted multi-value non-option of that same type. // ///Background for Unix-Style Command-Line Arguments and Definitions ///---------------------------------------------------------------- // This section provides background on Unix-style command-line arguments, as // well as definitions of terms used frequently in this documentation (such as // "option", "flag", "non-option", "tag", "short tag", "long tag"). Readers // familiar with Unix command lines can skim this section or omit entirely. // // Command-line arguments can be classified as: // //: o command name (there is only one, and it is always the first argument) //: o options (tags and associated values) //: o flags (boolean options) //: o non-option arguments // // For example, in the following command line: //.. // $ mybuildcommand -e -c CC64 myproject //.. // the command name is 'mybuildcommand'. There is one option, described by // '-c CC64': 'c' is the tag name, and 'CC64' is the option value. There is // also one boolean option (flag): '-e' is a flag, 'e' is the flag name. The // last parameter, 'myproject', is a non-option argument. // // Sometimes *option* is also used where "flag" or "non-option" would be more // accurate. What is actually intended should be clear from context. // // A user specifies an option on a command line by entering one of the tag // values configured for that option. Each option has a mandatory long tag and // an optional short tag. The short tag, if specified, must be a single // alphabet symbol; the long tag generally must follow the same rules // applicable to C/C++ identifiers, except that '-' is allowed (but not as the // leading character). When a short tag is used on a command line, it must be // preceded by '-', and when a long tag is used it must be preceded by '--'. // Flags have no corresponding values; they are either present or absent. // Option tags *must* be followed by a corresponding option value. An option // can have multiple values (such options are called multi-valued options). // When multiple values are provided for an option, the tag must appear with // each value (see the section {Multi-Valued Options and How to Specify Them}). // Arguments that are not the command name, options, or flags are called // "non-option" arguments and can be either single-valued or multi-valued. // They do not have any tag associated with them. // // Consider the syntax of a typical Unix-style command whose options are // described by the usage string: //.. // usage: mysort [-r|reverse] [-o|outputfile <outfile>] files... //.. // Here: //.. // '-r|reverse' is a flag: 'r' is the short tag, 'reverse' is the long tag. // // '-o|outputfile' is an option: 'o' is the short tag, 'outputfile' is the // long tag. The value is parsed from the string 'outfile'. // // 'files...' describes the multi-valued non-option argument. //.. // The command can be invoked as follows: //.. // $ mysort -r -o myoutfile file1 file2 file3 //.. // and an equivalent command line is: //.. // $ mysort --reverse --outputfile myoutfile file1 file2 file3 //.. // Note that short tags must be prepended with '-' and long tags with '--'. To // specify a non-option argument beginning with '-', use a single '--' // separator (not followed by a long tag). // ///Specifying Option Values ///------------------------ // This component supports a variety of forms for specifying option values. // They are best described by example. Consider the command-line specification // described by the following usage string: //.. // usage: myserver [-p|port <portNumber>] //.. // The following (valid) forms can be used with equivalent meaning: //.. // $ myserver -p 13 // $ myserver -p=13 # option value is '13' and *not* '=13' // $ myserver -p13 // $ myserver --port 13 // $ myserver --port=13 //.. // Note that if '=13' is desired as an option value, then whitespace must be // used as in: //.. // $ myserver -p =13 # option value *is* '=13' //.. // All of the following are invalid: //.. // $ myserver -port13 // $ myserver --p 13 // $ myserver -port 13 //.. // ///Flag Grouping ///------------- // Flags can be grouped (i.e., expressed more succinctly like '-ctv' instead of // '-c -t -v'). While grouping flags, short tags must be used. For example, // given the command-line specification described by the following usage // string: //.. // usage: mysort [-r|reverse] [-i|insensitiveToCase] [-u|uniq] //.. // the following command lines are valid and equivalent: //.. // $ mysort -r -i -u // $ cmd -riu // $ cmd -uir // $ cmd -i -ru //.. // Note that the last character in a group need not be a flag; it could be an // option. Any character that is the short tag of an option signals the end of // the flag group, and it must be followed by the value of the option. For // example, given the command-line specification described by the following // usage string: //.. // usage: mysort [-r|reverse] [-i|insensitiveToCase] [-u|uniq] // [-o|outfile <outputfile>] //.. // the following command lines are valid and equivalent: //.. // $ mysort -riu -o myoutfile // $ mysort -riuo myoutfile // $ mysort -riuomyoutfile // $ mysort -riuo=myoutfile //.. // ///Multi-Valued Options and How to Specify Them ///-------------------------------------------- // Options can have several values. For example, in the command-line // specification described by the following usage string, '*' denotes a // multi-valued option, and '+' denotes a multivalued option that must occur at // least once. //.. // usage: mycompiler [-l|library <libName>]* [-o|out outFile] [<object>]+ //.. // multiple values can be given as follows: //.. // $ mycompiler -l lib1 -l lib2 -l lib3 -o main a.o b.o //.. // They need not be supplied contiguously. For example, the following command // line is valid and equivalent to the above: //.. // $ mycompiler -l lib1 -o main -l lib2 -l lib3 a.o b.o //.. // Note that the tag needs to be repeated for every option value. For example, // the following command line is invalid (because '-l' must be repeated before // both 'lib2' and 'lib3'): //.. // $ mycompiler -l lib1 lib2 lib3 -o main a.o b.o //.. // Short and long forms can be used in mixed fashion, however: //.. // $ mycompiler -l lib1 -o main --library lib2 -l lib3 a.o b.o //.. // ///Order of Arguments ///------------------ // Command-line arguments can appear in any order. For example, given the // command-line specification described by the following usage string: //.. // usage: mysort [-r|reverse] [-o|outputfile <outfile>] [<file>]+ //.. // all the following command lines are valid (and equivalent): //.. // $ mysort -r -o myoutfile file1 file2 file3 // $ mysort file1 file2 file3 -r -o myoutfile // $ mysort file1 -o myoutfile file2 -r file3 // $ mysort file1 -o=myoutfile file2 -r file3 //.. // There are three exceptions to the above rule on argument order: // //: 1 An option tag must be followed by that option's value, if any (either in //: the next argument, or in the same argument using "=value"). //: //: 2 When a non-option argument starts with a '-' then it must not appear //: before any option or flag *and* a '--' must be put on the command line to //: indicate the end of all options and flags. //: //: 3 Non-option arguments are parsed and assigned in the order they appear on //: the command line. // // For example, the following is invalid because of rule (1) above (because // '-o' should be followed by 'myoutfile'): //.. // $ mysort -o -r myoutfile file1 file2 file3 //.. // and the following is incorrect because of rule (2) (because // '-weirdfilename', which starts with '-', must appear after '--'): //.. // $ mysort -weirdfilename file2 file3 -r -o myoutfile //.. // The previous examples can be corrected in either of the following ways: //.. // $ mysort -r -o myoutfile -- -weirdfilename file2 file3 // $ mysort file2 file3 -r -o myoutfile -- -weirdfilename //.. // Note that the order of values within the sequence of multi-valued non-option // arguments differs in both examples, as per rule (3). In the first example, // the non-option arguments have for a value the (ordered) sequence: //.. // -weirdfilename file2 file3 //.. // while in the second example, the non-option argument value is the sequence: //.. // file2 file3 -weirdfilename //.. // This order may or may not matter to the application. // ///Specifying Command-Line Arguments ///--------------------------------- // A command line is described by an *option* *table* (supplied as an array of // 'balcl::OptionInfo'). Each entry (row) of the table describes an option // (i.e., an option, flag, or non-option argument). Each entry has several // fields, specified in the following order: //.. // Field name Main purpose (see below for more details) // ============================ =========================================== // tag field Specify tags (short and long) for options // and flags. A non-option argument is // indicated by an empty string. // // name field Specify the name through which the option // value can be accessed. // // description field Used in printing usage. // // type-and-constraint field (1) Specify the type of the option value(s). // (2) Specify a variable to be linked to the // option. // (3) Specify other constraints on individual // value(s). // // occurrence information field (1) Specify a default value for an option. // (2) Specify whether an option is required on // the command line or is optional (by // default, an option is optional). //.. // The first three fields *must* be specified. The type-and-constraint field // can be omitted (meaning no constraint), and the occurrence information field // likewise can be omitted (meaning that the option is not required on the // command line). // // The following sections provide a more detailed description of each field, // including example values for each field. // ///'balcl::OptionInfo' versus 'balcl::Option' /// - - - - - - - - - - - - - - - - - - - - - // In some applications, command-line specifications *must* *be* defined using // a statically-initialized array. For that reason, there are two classes that // serve the same purpose: 'balcl::OptionInfo' is a statically-initializable // class but it does not conform to the 'bslma' allocator protocol, while // 'balcl::Option' is convertible from 'balcl::OptionInfo', takes allocators, // and is suitable for storing into containers. // ///Tag Field ///- - - - - // The tag field specifies the (optional) short tag and long tag for the // corresponding option or flag, except that non-option arguments are indicated // by an empty string for a tag field. There can only be one multi-valued // entry for non-option arguments, and it must be listed last among the // non-options. // // The general format is either: //: 1 "" (empty string) for non-option arguments; //: 2 "<s>|<long>" for options and flags, where '<s>' is the short tag, and //: '<long>' is the long tag; or //: 3 "<long>" for options and flags where a short tag is not specified. // // Note that for short tags ('<s>'), 's' must be a single character (different // from '-' and '|'); for long tags ("<long>"), 'long' must have 2 or more // characters (which may contain '-', except as the first character, but cannot // contain '|'). Also note that either no tag (empty string), both short and // long tags, or only a long tag, may be specified. // // The tag field cannot be omitted, but it can be the empty string. // ///Name Field /// - - - - - // The name field specifies the name through which the option value can be // accessed either through one of the *theType* methods or through the handle // returned by the 'options' method. // // The general format is any non-empty string. In most cases, the name will be // used as-is. Note that any suffix starting at the first occurrence of '=', // if any, is removed from the name before storing in the 'balcl::OptionInfo'. // Thus, if a name having such a suffix is specified in a 'balcl::OptionInfo' // (e.g., "nameOption=someAttribute"), the correct name to use for querying // this option by name (e.g., through the 'options' handle) does not include // the suffix (e.g., 'cmdLine.numSpecified("nameOption=someAttribute")' will // always return 0, but 'cmdLine.numSpecified("nameOption")' will return the // appropriate value). // // This field cannot be omitted, and it cannot be an empty string. // ///Description Field ///- - - - - - - - - // The description field is used when printing the usage string. // // The general format is any non-empty string. // // This field cannot be omitted, and it cannot be an empty string. // ///Type-and-Constraint Field ///- - - - - - - - - - - - - // The type-and-constraint field specifies the type and constraints for the // option values. Flags are identified by having the boolean type; note that // flags cannot have constraints. Multiple values (for multi-valued options // and multi-valued non-option arguments) can be specified by using array // types. The list of the supported types is provided in the section // {Supported Types} below. // // Other constraints can be placed on individual value(s). When the type is an // array type, then those constraints are placed on the individual value(s) // held in the array and not on the entire array. A list of useful constraints // is provided in the section {Supported Constraint Values}. Also see the // section {Building New Constraints} to see how new constraints can be built // so that they can be used in the same manner as the available constraints. // // Additionally, this field allows a specified variable to be linked to the // option. In that case, after parsing, the variable is loaded with the option // value specified on the command line (or its default value, if any, if the // option is absent from the command line). {Occurrence Information Field} // describes how to configure a default value. // // The general format can be one of either: //.. // balcl::TypeInfo(&variable) // balcl::TypeInfo(&variable, constraint) // // Link the option with the specified 'variable'. Note that the option // // type is inferred from the type of 'variable'. Optionally place the // // user-specified 'constraint', of a type defined in // // 'balcl::Constraint', on the value. // // balcl::TypeInfo(type) // balcl::TypeInfo(type, constraint) // // Specify the type of this option to be of the specified 'type'. // // Optionally place the user-specified 'constraint', of a type defined // // in 'balcl::Constraint', on the value. Don't link this // // option with any variable. 'type' must be one of the static // // variables (null pointers) listed in // // {'balcl_optiontype'|Enumerators}. //.. // This field can be omitted. If so, the type is assumed to be of string type // with no constraints and no variable is linked to the option. No occurrence // information field can then be specified; if such a field is desired, then // the type-and-constraint field needs to be set explicitly. // ///Linked Variables ///- - - - - - // Linked variables are updated by the 'parse' method of 'balcl::CommandLine' // should that method determine a value for an option; otherwise, the linked // variable is left unchanged. The value for an option is determined either // from the command-line arguments passed to 'parse' or obtained from a // pre-configured default value, if any (see {Occurrence Information Field}). // // Linked variables can be 'bsl::optional' objects that wrap any of the // non-array option types except for 'bool' (see {Supported Types}). Also, a // link to a 'bsl::optional' object is disallowed if the option is "required" // or has a default value (see {Occurrence Information Field}). // ///Occurrence Information Field /// - - - - - - - - - - - - - - // The occurrence information field is used to specify a default value for an // option, and whether an option is required on the command line or is // optional. An option may also be "hidden" (i.e., not displayed by // 'printUsage'). // // The general format of this field is one of the following: //.. // balcl::OccurrenceInfo::e_HIDDEN // balcl::OccurrenceInfo::e_OPTIONAL // balcl::OccurrenceInfo::e_REQUIRED // a default value //.. // If a default value is specified, the option is assumed to be optional; in // addition, the default value must satisfy the type and constraint indicated // by the specified type-and-constraint field. // // This field can be omitted, and is always omitted if the type-and-constraint // field is not specified. If omitted, the option is not required on the // command line and has no default value; furthermore, if the option is not // present on the command line, the linked variable, if any, is unaffected. // ///Example Field Values ///-------------------- // The following tables give examples of field values. // ///Example: Tag Field /// - - - - - - - - - // The tag field may be declared using the following forms: //.. // Usage Meaning // ============== ======================================================= // "o|outputfile" The option being defined is either an option or a flag. // The short tag is "o" and the long tag is "outputfile". // // Note that "o" alone is invalid since a long tag must be // specified. // // "outputfile" The option being defined is either an option or a flag. // There is no short tag and the long tag is "outputfile". // // "" Specifies a non-option argument. //.. // ///Example: Name Field ///- - - - - - - - - - // The name field may be declared using the following form: //.. // Usage Meaning // =============== ======================================================= // "xyz" The option value can be accessed by "xyz". //.. // ///Example: Type-and-Constraint Field /// - - - - - - - - - - - - - - - - - // Suppose, for example, that our application has the following parameters: //.. // int portNum; // a variable to be linked to an // // option // // bool isVerbose; // a variable to be linked to a flag // // bsl::vector<bsl::string> fileNames; // a variable to be linked to a // // multi-valued option //.. // The type and constraint fields may be declared using the following values: //.. // Usage Meaning // =============== ======================================================= // balcl::TypeInfo(&portNum) // (1) Link the variable 'portNum' with this option value. // That is, after successful parsing, this variable will // contain the option value specified on the command line. // (2) An integer value must be provided on the command // line for this option (the type 'int' is inferred // implicitly from the type of 'portNum'). // // balcl::TypeInfo(balcl::OptionType::k_INT) // This option value must be an integer. // // balcl::TypeInfo(&isVerbose) // Load the variable 'isVerbose' with this option value. // // balcl::TypeInfo(balcl::OptionType::k_BOOL) // This option is a flag. // // balcl::TypeInfo(&fileNames) // Load the variable 'fileNames' with the values specified // for this multi-valued option (or multi-valued // non-option argument). That is, after successful parsing, // this variable will contain the sequence of values // specified on the command line, in the same order. // // balcl::TypeInfo(balcl::OptionType::k_STRING_ARRAY) // This option value consists of a sequence of string // values specified on the command line, in the same order. //.. // ///Example: Occurrence Information Field ///- - - - - - - - - - - - - - - - - - - // The following values may be used for this field: //.. // Usage Meaning // =============== ======================================================== // balcl::OccurrenceInfo::e_REQUIRED // The value(s) for this option *must* be provided on the // command line. For options that are of an array type, at // least one value must be provided. Omission manifests // as a parse error. // // balcl::OccurrenceInfo::e_OPTIONAL // Value(s) for this option may be omitted on the command // line. // // balcl::OccurrenceInfo::e_HIDDEN // Same as 'e_OPTIONAL'; in addition, this option will not // be displayed by 'printUsage'. // // 13 The default value for this option is 13 and the option // is not required on the command line. If no value is // provided, then 13 is used. If the type described by the // type-and-constraint field is not integer, then it is an // error. //.. // *Note*: If an option is optional *and* no value is provided on the command // line, then it will be in a null state (defined type but *no* defined value) // in the handle returned by either 'options' or 'specifiedOptions'. In // addition, if a variable was linked to this option, it will be unmodified // after parsing. // ///Supported Types ///--------------- // The following types are supported. The type is specified by an enumeration // value (see {'balcl_optiontype'}) supplied as the first argument to: //.. // balcl::TypeInfo(type, constraint) //.. // which is used to create the type-and-constraint field value in the // command-line specification. When the constraint need only specify the type // of the option value (i.e., no linked variable or programmatic constraint), // one can supply any of the public data members of 'balcl::OptionType' shown // below: //.. // Type Specifier // ----------------------------- ------------------------- // bool OptionType::k_BOOL // char OptionType::k_CHAR // int OptionType::k_INT // bsls::Types::Int64 OptionType::k_INT64 // double OptionType::k_DOUBLE // bsl::string OptionType::k_STRING // bdlt::Datetime OptionType::k_DATETIME // bdlt::Date OptionType::k_DATE // bdlt::Time OptionType::k_TIME // bsl::vector<char> OptionType::k_CHAR_ARRAY // bsl::vector<int> OptionType::k_INT_ARRAY // bsl::vector<bsls::Types::Int64> OptionType::k_INT64_ARRAY // bsl::vector<double> OptionType::k_DOUBLE_ARRAY // bsl::vector<bsl::string> OptionType::k_STRING_ARRAY // bsl::vector<bdlt::Datetime> OptionType::k_DATETIME_ARRAY // bsl::vector<bdlt::Date> OptionType::k_DATE_ARRAY // bsl::vector<bdlt::Time> OptionType::k_TIME_ARRAY //.. // The ASCII representation of these values (i.e., the actual format of the // values on command lines) depends on the type: //: o Numeric Values: see {'bdlb_numericparseutil'}. //: o Date/Time Values: see {'bdlt_iso8601util'}. // ///Supported Constraint Values ///--------------------------- // This component supports constraint values for each supported type except // 'bool'. Specifically, the utility 'struct' 'balcl::Constraint' defines // 'TYPEConstraint' types (for instance, 'StringConstraint', 'IntConstraint') // that can be used to define a constraint suitable for the 'balcl::TypeInfo' // class. // ///Building New Constraints ///------------------------ // A constraint is simply a function object that takes as its first argument // the (address of the) data to be constrained and as its second argument the // stream that should be written to with an appropriate error message when the // data does not follow the constraint. The functor should return a 'bool' // value indicating whether or not the data abides by the constraint (with // 'true' indicating success). A constraint for a given option whose value has // the given type must be convertible to one of the 'TYPEConstraint' types // defined in the utility 'struct' 'balcl::Constraint'. Note that when passing // a function as a constraint, the *address* of the function must be passed. // ///Valid 'balcl::OptionInfo' Specifications ///---------------------------------------- // The 'balcl::CommandLine' class has a complex set of preconditions on the // option specification table (array of 'balcl::OptionInfo' objects) passed to // each of its constructors. There are requirements on individual elements, on // elements relative to each other, and on the entire set of elements. If // these preconditions are not met, the behavior of the constructor is // undefined. // // The preconditions (some previously mentioned) are given in their entirety // below. Moreover, an overloaded class method, // 'balcl::CommandLine::isValidOptionSpecification', is provided to allow // programmatic checking without risk of incurring undefined behavior. // ///Tag/Name/Description Fields ///- - - - - - - - - - - - - - // The tag, name, and description fields must pass the 'isTagValid', // 'isNameValid, and 'isDescriptionValid' methods of 'balcl::Option', // respectively. // //: o The tag field: //: o If empty (a non-option argument), the option must not be a flag. //: o If non-empty, see {Tag Field} above for details. //: o The name field must be non-empty. //: o The description field must be non-empty. // // Collectively, each non-empty short tag, each long tag, and each name must be // unique in the specification. // ///Default Values /// - - - - - - - //: o Default values are disallowed for flags. //: o The type of a default value must match the type of its option. //: o The default value must satisfy the user-defined constraint on the option //: value, if any. // ///Non-Option Arguments /// - - - - - - - - - - //: o Cannot be a flag (see {Tag/Name/Description Fields}). //: o Cannot be a hidden option. //: o Only the last non-option argument can be multi-valued (i.e., an array //: type). //: o If a non-option argument has a default value, all subsequent non-option //: arguments must also have default values. // ///Boolean Options (Flags) ///- - - - - - - - - - - - // Options having the 'bool' type (also known as "flags") are distinguished // from the other supported option types in several ways: // //: o The command-line syntax does not allow an explicit value for flag types //: (e.g., '-x=true' and '-xFlag false' are disallowed). The presence or //: absence of the tag name (either long or short form) on the command line //: determines the value of the option. //: //: o The boolean option type has no "array" form (i.e., there is no //: 'BoolArray' option type). //: //: o Multiple instances of the tag for a boolean option are allowed on the //: command line (e.g., '-x -x -x'). For other option types, specifying //: multiple tags for a non-array option is an error. //: //: o Multiple instances of a boolean tag idempotently set the flag to //: 'true'; however, one can determine the number of appearances by using //: the 'position' accessor. //: //: o A boolean option type cannot be configured to: //: o have a default value, or //: o have a constraint, or //: o be linked to a 'bsl::optional<bool>' variable. //: //: o A boolean option type *can* be configured to be a required parameter; //: however, that combination defeats the purpose of having a flag option so //: the requirement that the flag appear on the command line is *not* //: enforced. //: //: o The 'theBool' method returns the same value ('true' or 'false') as the //: 'isSpecified' method. In contrast, the 'the*' accessor methods for the //: other option types have a precondition such that either 'isSpecified()' //: must be 'true' or the option must have a default value. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Using Command Line Features In Concert ///- - - - - - - - - - - - - - - - - - - - - - - - - // Suppose we want to design a sorting utility named 'mysort' that has the // following syntax: //.. // usage: mysort [-r|reverse] [-i|insensitivetocase] [-u|uniq] // [-a|algorithm sortAlgo] -o|outputfile <outputFile> // [-t|field-separator] <character> // [<file>]* // // Sort the specified files (in 'fileList'), // // using the specified sorting algorithm and // // write the output to the specified output file. // // option note // ============ ==================================================== // -a|algorithm (1) Value (provided on command line) of this option must // be one among "quickSort", "insertionSort", "shellSort". // (2) If not provided, default value will be "quickSort". // // -o|outfile (1) This option must not be omitted on command line. //.. // We choose the non-option argument to be an array of 'bsl::string' so as to // accommodate multiple files. // // These options might be used incorrectly, as the following examples show: //.. // INCORRECT USE REASON FOR INACCURACY // =========================================== ============================ // $ mysort -riu -o myofile -aDUMBSORT f1 f2 Incorrect because 'DUMBSORT' // is not among valid values // for the -a option. // // $ mysort -riu f1 f2 Incorrect because no value // is provided for the -o option. //.. // In order to enforce the constraint on the sorting algorithms that are // supported, our application provides the following free function: //.. // bool isValidAlgorithm(const bsl::string *algo, bsl::ostream& stream) // // Return 'true' if the specified 'algo' is one among "quickSort", // // "insertionSort", and "shellSort"; otherwise, output to the specified // // 'stream' an appropriate error message and return 'false'. // { // if ("quickSort" == *algo || "insertionSort" == *algo // || "shellSort" == *algo) { // return true; // RETURN // } // stream << "Error: sorting algorithm must be either " // "'quickSort', 'insertionSort', or 'shellSort'.\n"; // return false; // } //.. // Using this function, we can now use a 'balcl::CommandLine' object to parse // command-line options. The proper usage is shown below. First we declare // the variables to be linked to the options. If they are needed at global // scope, we could declare them as global variables, but we prefer to declare // them as local variables inside 'main': //.. // int main(int argc, const char *argv[]) { //.. // Then, we define local variables that will be linked to certain command-line // options. If those options are specified on the command line (or if a // default is specified via 'balcl::OccurrenceInfo'), these variables are // updated; otherwise, these variables are left unchanged. //.. // bool isReverse = false; // Must be initially 'false'. // bool isCaseInsensitive = false; // Must be initially 'false'. // bool isUniq = false; // Must be initially 'false'. // // bsl::optional<char> fieldSeparator; // bsl::string outFile; // bsl::string sortAlgo; // bsl::vector<bsl::string> files; //.. // Notice that variables linked to flags (boolean options) are initialized to // 'false'; otherwise, these variables would show incorrect values (i.e., // 'true') if their corresponding tags are absent from the command line. // // Next, we build up an option specification table as follows: //.. // // build constraint for sortAlgo option // balcl::Constraint::StringConstraint validAlgoConstraint( // &isValidAlgorithm); // // // option specification table // balcl::OptionInfo specTable[] = { // { // "r|reverse", // tag // "isReverse", // name // "sort in reverse order", // description // balcl::TypeInfo(&isReverse), // link // balcl::OccurrenceInfo::e_OPTIONAL // occurrence info // }, // { // "i|insensitivetocase", // tag // "isCaseInsensitive", // name // "be case insensitive while sorting", // description // balcl::TypeInfo(&isCaseInsensitive), // link // balcl::OccurrenceInfo::e_OPTIONAL // occurrence info // }, // { // "u|uniq", // tag // "isUniq", // name // "discard duplicate lines", // description // balcl::TypeInfo(&isUniq), // link // balcl::OccurrenceInfo::e_OPTIONAL // occurrence info // }, // { // "t|field-separator", // tag // "fieldSeparator", // name // "field separator character", // description // balcl::TypeInfo(&fieldSeparator), // link // balcl::OccurrenceInfo::e_OPTIONAL // occurrence info // }, // { // "a|algorithm", // tag // "sortAlgo", // name // "sorting algorithm", // description // balcl::TypeInfo(&sortAlgo, validAlgoConstraint), // // link and // // constraint // balcl::OccurrenceInfo(bsl::string("quickSort")) // // default // // algorithm // }, // { // "o|outputfile", // tag // "outputFile", // name // "output file", // description // balcl::TypeInfo(&outFile), // link // balcl::OccurrenceInfo::e_REQUIRED // occurrence info // }, // { // "", // non-option // "fileList", // name // "files to be sorted", // description // balcl::TypeInfo(&files), // link // balcl::OccurrenceInfo::e_OPTIONAL // occurrence info // } // }; //.. // We can now create a command-line specification and parse the command-line // options: //.. // // Create command-line specification. // balcl::CommandLine cmdLine(specTable); // // // Parse command-line options; if failure, print usage. // if (cmdLine.parse(argc, argv)) { // cmdLine.printUsage(); // return -1; // RETURN // } //.. // Upon successful parsing, the 'cmdLine' object will acquire a value that // conforms to the specified constraints. We can examine these values as // follows: //.. // // If successful, obtain command-line option values. // balcl::CommandLineOptionsHandle options = cmdLine.options(); // // // Access through linked variable. // bsl::cout << "outFile: " << outFile << bsl::endl; // bsl::cout << "isUniq: " << isUniq << bsl::endl; // if (fieldSeparator.has_value()) { // bsl::cout << "fieldSeparator: " // << fieldSeparator.value() << bsl::endl; // } // // // Access through *theType* methods. // assert(cmdLine.theString("outputFile") == outFile); // // // Access through 'options'. // assert(options.theString("outputFile") == outFile); // // // Check that required option has been specified once. // assert(cmdLine.isSpecified("outputFile")); // // int count = -1; // assert(cmdLine.isSpecified("outputFile", &count)); // assert(1 == count); // // return 0; // } //.. // For instance, the following command lines: //.. // $ mysort -omyofile f1 f2 f3 // $ mysort -ainsertionSort f1 f2 f3 -riu -o myofile outputFile // $ mysort --algorithm insertionSort --outputfile myofile f1 f2 f3 --uniq //.. // will all produce the same output on 'stdout'. #include <balscm_version.h> #include <balcl_option.h> #include <balcl_optioninfo.h> #include <balcl_optiontype.h> #include <balcl_optionvalue.h> #include <bdlb_printmethods.h> #include <bslmf_nestedtraitdeclaration.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bsls_assert.h> #include <bsls_types.h> #include <bsl_cstddef.h> // 'bsl::size_t' #include <bsl_cstring.h> // 'bsl::strcmp' #include <bsl_iosfwd.h> #include <bsl_sstream.h> // 'bsl::ostringstream' #include <bsl_string.h> #include <bsl_vector.h> #include <bdlt_date.h> #include <bdlt_datetime.h> #include <bdlt_time.h> namespace BloombergLP { namespace balcl { // ============================= // struct CommandLine_SchemaData // ============================= struct CommandLine_SchemaData{ // This 'struct', a pure value-semantic type, is used to manage option // value type and name information in support of public interfaces to // parsed options. See 'CommandLineOptionsHandle'. // PUBLIC DATA OptionType::Enum d_type; // option data type const char *d_name_p; // option name }; // FREE OPERATORS bool operator==(const CommandLine_SchemaData& lhs, const CommandLine_SchemaData& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'CommandLine_SchemaData' objects have the same // value if their 'type' attributes are the same and if their 'name' // attributes compare equal. bool operator!=(const CommandLine_SchemaData& lhs, const CommandLine_SchemaData& rhs); // Return 'true' if the specified 'lhs' and 'rhs' do note have the same // value, and 'false' otherwise. Two 'CommandLine_SchemaData' objects do // not have the same value if their 'type' attributes are not the same or // if their 'name' attributes do not compare equal. // ================= // class CommandLine // ================= class CommandLineOptionsHandle; class CommandLine { // This value-semantic 'class' parses, validates, and provides access to // command-line arguments. The constructor takes the specification // describing the command-line arguments. Once created, 'printUsage' can // be invoked to print the usage syntax. The 'parse' method takes // command-line arguments and validates them against the specification // provided at creation, writing a suitable message to an // optionally-specified stream in case of a parsing error. Once parsed, // options and values can be accessed using various accessors. The class // has a set of 'theType' methods (e.g., 'theString', 'theInt') that // provide access, by name, to the value of the indicated option. It is // also possible to link a variable with an option in the specification; // doing so will cause the variable to be loaded with the option value once // 'parse' has been invoked. The 'options' method returns a // 'balcl::CommandLineOptionsHandle' object referring to the option names // and their values. A similar but different method, 'specifiedOptions', // is suitable for overwriting other configuration parameters (possibly // obtained from a configuration file). // PRIVATE TYPES typedef bsl::vector<CommandLine_SchemaData> CommandLine_Schema; typedef bsl::vector<OptionValue> OptionValueList; enum State { e_INVALID = 0, e_PARSED = 1, e_NOT_PARSED = 2 }; // DATA bsl::vector<Option> d_options; // command-line options // specified at // construction bsl::vector<bsl::vector<int> > d_positions; // set of positions of // each command-line // option in the // arguments specified to // 'parse', indexed by // position of option in // 'd_options' bsl::vector<int> d_nonOptionIndices; // set of positions of // each command-line // non-option in the // arguments specified to // 'parse', indexed by // non-option rank in // 'd_options' State d_state; // indicates whether // 'parse' was invoked, // and with what result bsl::vector<bsl::string> d_arguments; // command-line arguments // specified to 'parse' CommandLine_Schema d_schema; // schema describing the // structure of the // option values in the // returned handle OptionValueList d_data; // primary option values, // recorded one by one as // they are parsed by the // 'parse' manipulator OptionValueList d_data1; // final option values, // copied from 'd_data' // and from default // values by 'postParse' mutable OptionValueList d_data2; // specified data, i.e., // 'd_data1' with // non-specified // arguments reset, // created by the // 'specifiedOptions' // manipulator mutable bool d_isBindin2Valid; // records whether // 'd_data2' was // initialized by // 'specifiedOptions' private: // PRIVATE MANIPULATORS void clear(); // Reset this command-line object to an uninitialized state. Note that // the state is set to 'INVALID' and not 'NOT_PARSED'. void initArgs(int argc, const char *const argv[]); // Store the specified 'argc' entries from the specified 'argv' array // of command-line arguments in this object. int parse(bsl::ostream& stream); // Parse the command-line arguments one-by-one, matching them against // the appropriate options, setting the primary option values along the // way. Return 0 if parsing succeeds, and a non-zero value otherwise. // Upon encountering an error, output to the specified 'stream' a // descriptive error message and abort parsing subsequent arguments. int postParse(bsl::ostream& stream); // Verify that all required arguments have been given a value, and in // that case load all the primary option values (if set) or default // option values (if the primary option value is optional and set by no // command-line argument) into the final option values and set the // linked variables, if any. Return 0 on success, and a non-zero value // if not all required arguments are provided with a value (and in this // case, leave the final option values and linked variables unchanged). // Upon encountering an error, output to the specified 'stream' a // descriptive error message and abort parsing subsequent arguments. void validateAndInitialize(); void validateAndInitialize(bsl::ostream& stream); // Validate the command-line options passed at construction with // respect to the command-line documented invariants (e.g., valid tags, // names, and descriptions, default values satisfying constraints, // uniqueness of tags and names, and miscellaneous constraints), and // initialize all internal state for parsing. Optionally specify an // output 'stream'. If 'stream' is not specified, 'bsl::cerr' is used. // Upon encountering errors, output descriptive error messages and // abort the execution of this program by invoking the currently // installed assertion handler (unconditionally). Note that this // method will attempt to report as many errors as possible before // aborting, but that correcting all these errors will not guarantee // that subsequent execution would result in successful validation. // PRIVATE ACCESSORS int findName(const bsl::string_view& name) const; // Return the index (in the options table passed at construction) of an // option whose name matches the specified 'name' string, or -1 if no // such 'name' exists. int findTag(const bsl::string_view& longTag) const; // Return the index (in the options table passed at construction) of a // command-line option whose long tag matches the specified 'longTag' // string of the specified 'tagLength', or -1 if no such 'longTag' // exists. int findTag(char shortTag) const; // Return the index (in the options table passed at construction) of an // option whose short tag matches the specified 'shortTag' character, // or -1 if no such 'shortTag' exists. void location(bsl::ostream& stream, int index, int start = -1, int end = -1) const; // Output to the specified 'stream' a message describing the location // in the argument at the specified 'index' (in the list of // command-line arguments) where an error was found. Optionally // specify a 'start' character position in that argument; if 'start' is // specified, optionally specify an 'end' character position as well. int longestNonFlagNameSize() const; // Return the length of the longest name in all the possible non-flag // options of this command line. int longestTagSize() const; // Return the length of the longest long tag in all the possible // options of this command line. Note that short tags are ignored. int missing(bool checkAlsoNonOptions = true) const; // Check that all required options have already been parsed. // Optionally specify 'checkAlsoNonOptions'. If 'checkAlsoNonOptions' // is 'true' or not specified, required non-option arguments that have // not been parsed will also be returned; if 'false', they will be // ignored. Return the index of the first missing option, or -1 if // none. public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(CommandLine, bslma::UsesBslmaAllocator); BSLMF_NESTED_TRAIT_DECLARATION(CommandLine, bdlb::HasPrintMethod); // CLASS METHODS template <int LENGTH> static bool isValidOptionSpecificationTable( const OptionInfo (&specTable)[LENGTH]); template <int LENGTH> static bool isValidOptionSpecificationTable( OptionInfo (&specTable)[LENGTH]); template <int LENGTH> static bool isValidOptionSpecificationTable( const OptionInfo (&specTable)[LENGTH], bsl::ostream& stream); template <int LENGTH> static bool isValidOptionSpecificationTable( OptionInfo (&specTable)[LENGTH], bsl::ostream& stream); // Return 'true' if the specified (statically-initialized) 'specTable' // of the specified 'LENGTH' has a valid set of command-line option // specifications, and 'false' otherwise. Optionally specify 'stream' // to which error messages are written. If no 'stream' is specified, // this method produces no output. See {Valid 'balcl::OptionInfo' // Specifications} for a description of the validity requirements. static bool isValidOptionSpecificationTable(const OptionInfo *specTable, int length); static bool isValidOptionSpecificationTable(const OptionInfo *specTable, int length, bsl::ostream& stream); // Return 'true' if the specified 'specTable' of the specified 'length' // has a valid set of command-line option specifications, and 'false' // otherwise. Optionally specify 'stream' to which error messages are // written. If no 'stream' is specified, this method produces not // output. See {Valid 'balcl::OptionInfo' Specifications} for a // description of the validity requirements. The behavior is undefined // unless '0 <= length'. Note that 'specTable' need not be statically // initialized. // CREATORS template <int LENGTH> CommandLine(const OptionInfo (&specTable)[LENGTH], bsl::ostream& stream, bslma::Allocator *basicAllocator = 0); template <int LENGTH> CommandLine(OptionInfo (&specTable)[LENGTH], bsl::ostream& stream, bslma::Allocator *basicAllocator = 0); // Create an object accepting the command-line options described by the // specified (statically-initialized) 'specTable'. Optionally specify // a 'basicAllocator' used to supply memory. If 'basicAllocator' is 0, // the currently installed default allocator is used. The behavior is // undefined unless 'specTable' satisfies the // 'isValidOptionSpecificationTable' function. Note that an // appropriate error message is written to the specified 'stream'. template <int LENGTH> explicit CommandLine(const OptionInfo (&specTable)[LENGTH], bslma::Allocator *basicAllocator = 0); template <int LENGTH> explicit CommandLine(OptionInfo (&specTable)[LENGTH], bslma::Allocator *basicAllocator = 0); // Create an object accepting the command-line options described by the // specified (statically-initialized) 'specTable'. Optionally specify // a 'basicAllocator' used to supply memory. If 'basicAllocator' is 0, // the currently installed default allocator is used. The behavior is // undefined unless 'specTable' satisfies the // 'isValidOptionSpecificationTable' function. Note that an // appropriate error message is written to 'bsl::cerr'. CommandLine(const OptionInfo *specTable, int length, bslma::Allocator *basicAllocator = 0); // Create an object accepting the command-line options described by the // specified 'specTable' of the specified 'length'. Optionally specify // a 'basicAllocator' used to supply memory. If 'basicAllocator' is 0, // the currently installed default allocator is used. The behavior is // undefined unless 'specTable' satisfies the // 'isValidOptionSpecificationTable' function. Note that an // appropriate error message is written to 'bsl::cerr'. Also note that // 'specTable' need not be statically initialized. CommandLine(const OptionInfo *specTable, int length, bsl::ostream& stream, bslma::Allocator *basicAllocator = 0); // Create an object accepting the command-line options described by the // specified 'specTable' of the specified 'length'. Optionally specify // a 'basicAllocator' used to supply memory. If 'basicAllocator' is 0, // the currently installed default allocator is used. The behavior is // undefined unless 'specTable' satisfies the // 'isValidOptionSpecificationTable' function. Note that an // appropriate error message is written to the specified 'stream'. // Also note that 'specTable' need not be statically initialized. CommandLine(const CommandLine& original, bslma::Allocator *basicAllocator = 0); // Create a command-line object having the value of the specified // 'original' command line, if the 'original' is parsed, and otherwise // having a state such that parsing command-line arguments results in // the same value as parsing the same command-line arguments with the // 'original'. Optionally specify a 'basicAllocator' used to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. The behavior is undefined unless 'original' is // valid (i.e., 'original.isValid()' returns 'true'). ~CommandLine(); // Destroy this command-line object. // MANIPULATORS CommandLine& operator=(const CommandLine& rhs); // Assign to this command-line object the value of the specified 'rhs' // command-line object and return a reference providing modifiable // access to this object. The behavior is undefined unless both 'rhs' // and this object are valid (i.e., 'isValid()' and 'rhs.isValid()' // both return 'true'). int parse(int argc, const char *const argv[]); int parse(int argc, const char *const argv[], bsl::ostream& stream); // Parse the command-line arguments contained in the array starting at // the specified 'argv' having the specified 'argc' length. Optionally // specify a 'stream' to which an appropriate error message is written // if parsing fails. If 'stream' is not specified, 'bsl::cerr' is // used. Return 0 on success, and a non-zero value otherwise. After a // successful call 'true == isParsed()', 'true == isValid()', and the // information provided by 'argv' can be viewed via the accessors. // After an unsuccessful call 'false == isParsed()' and // 'false == isValid()'. The behavior is undefined unless // 'false == isParsed()' and 'true == isValid()'. Note that the // behavior is undefined if 'parse' is invoked more than once on an // object (successful or not). // ACCESSORS bool hasOption(const bsl::string_view& name) const; // Return 'true' if this command-line object is configured with an // option having the specified 'name', and 'false' otherwise. bool hasValue(const bsl::string_view& name) const; // Return 'true' if this command-line object's option having the // specified 'name' has a defined value, and 'false' otherwise. An // option has a defined value if 'isSpecified(name)' or if a default // value was configured for the option (see {Occurrence Information // Field}). The behavior is undefined unless this command-line object // 'isParsed()' and 'hasOption(name)'. bool isParsed() const; // Return 'true' if this object was parsed successfully, and 'false' // otherwise. Note that if 'parse' was invoked but failed, this method // returns 'false'. bool isSpecified(const bsl::string_view& name) const; bool isSpecified(const bsl::string_view& name, int *count) const; // Return 'true' if the option with the specified 'name' has been // entered on the command line and, if the optionally specified 'count' // is not 0, load into 'count' the number of times the option 'name' // has been entered on the command line; otherwise, return 'false' and // leave 'count' unaffected. Note that, in order to receive the valid // value, the command line must be successfully parsed. bool isValid() const; // Return 'true' if this object is in a valid state, and 'false' // otherwise. Objects are in a valid state after construction from a // valid set of option specifications (see the function-level // documentation of the 'isValidOptionSpecificationTable' method) and // after a successful invocation of the 'parse' method. Conversely, // construction from invalid option specifications or an unsuccessful // invocation of the 'parse' method leaves this object in an invalid // state. Note that additional object state is available from the // 'isParsed' accessor method. int numSpecified(const bsl::string_view& name) const; // Return the number of times the option with the specified 'name' has // been entered on the command line, or 0 if 'name' is not the name of // a field in the command-line specification passed at construction to // this object. Note that, in order to receive the valid number of // occurrences, the command line must be successfully parsed. CommandLineOptionsHandle options() const; // Return the command-line options and their values. If an option was // not entered on the command line *and* a default value was provided // for that option, then that default value will be used (note the // difference with the 'specifiedOptions' method). If an option was // not entered on the command line *and* no default value was provided // for that option, then the corresponding option will be in a null // state. The behavior is undefined unless 'isParsed' returns 'true'. int position(const bsl::string_view& name) const; // Return the position where the option with the specified 'name' has // been entered on the command line (i.e., the offset in the 'argv' // argument to the 'parse' method). If the option was not specified, // return -1. The behavior is undefined unless the option is of scalar // type. const bsl::vector<int>& positions(const bsl::string_view& name) const; // Return the positions where the option with the specified 'name' has // been entered on the command line (i.e., the offset in the 'argv' // argument to the 'parse' method). If the option was not specified, // return an empty vector. Note that, in order to receive the valid // positions, the command line must be successfully parsed. void printUsage() const; void printUsage(bsl::ostream& stream) const; // Print usage to the specified output 'stream', describing what the // command line should look like. If 'stream' is not specified, print // usage to 'stderr'. This method can be invoked at any time, even // before 'parse' has been invoked on this object. CommandLineOptionsHandle specifiedOptions() const; // Return the command-line options and their values. If an option was // not entered on the command line, then the option will be in a null // state (note the difference with the 'options' method). This method // is especially useful for overwriting some other configuration // (potentially obtained from a configuration file). The behavior is // undefined unless 'isParsed' returns 'true'. OptionType::Enum type(const bsl::string_view& name) const; // Return the type of the option having the specified 'name'. The // behavior is undefined unless this command-line object // 'hasOption(name)'. // 'the*' Accessors // BDE_VERIFY pragma: -FABC01 // not in alphabetic order bool theBool(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // value returned matches that returned by 'isSpecified(name)'. The // behavior is undefined unless this command-line object 'isParsed()', // 'hasOption(name)', and 'OptionType::e_BOOL == type(name)'. char theChar(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this command-line object 'isParsed()', // 'hasOption(name)', 'OptionType::e_CHAR == type(name)', and // 'hasValue(name)'. int theInt(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this command-line object 'isParsed()', // 'hasOption(name)', 'OptionType::e_INT == type(name)', and // 'hasValue(name)'. bsls::Types::Int64 theInt64(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this command-line object 'isParsed()', // 'hasOption(name)', 'OptionType::e_INT64 == type(name)', and // 'hasValue(name)'. double theDouble(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this command-line object 'isParsed()', // 'hasOption(name)', 'OptionType::e_DOUBLE == type(name)', and // 'hasValue(name)'. const bsl::string& theString(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_STRING == type(name)', and 'hasValue(name)'. const bdlt::Datetime& theDatetime(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_DATETIME == type(name)', and 'hasValue(name)'. const bdlt::Date& theDate(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_DATE == type(name)', and 'hasValue(name)'. const bdlt::Time& theTime(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_TIME == type(name)', and 'hasValue(name)'. const bsl::vector<char>& theCharArray(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_CHAR_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<int>& theIntArray(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_INT_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<bsls::Types::Int64>& theInt64Array( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_INT64_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<double>& theDoubleArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_DOUBLE_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<bsl::string>& theStringArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_STRING_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<bdlt::Datetime>& theDatetimeArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_DATETIME_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<bdlt::Date>& theDateArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_DATE_ARRAY == type(name)', and 'hasValue(name)'. const bsl::vector<bdlt::Time>& theTimeArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this // command-line object 'isParsed()', 'hasOption(name)', // 'OptionType::e_TIME_ARRAY == type(name)', and 'hasValue(name)'. // BDE_VERIFY pragma: +FABC01 // not in alphabetic order // Aspects bslma::Allocator *allocator() const; // Return the allocator used by this object to supply memory. Note // that if no allocator was supplied at construction the currently // installed default allocator at construction is used. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Format this command-line object to the specified output 'stream' at // the (absolute value of) the optionally specified indentation 'level' // and return a reference to 'stream'. If 'level' is specified, // optionally specify 'spacesPerLevel', the number of spaces per // indentation level for this object. If 'level' is negative, suppress // indentation of the first line. The behavior is undefined unless // '0 <= spacesPerLevel'. If 'stream' is not valid on entry, this // operation has no effect. }; // FREE OPERATORS bool operator==(const CommandLine& lhs, const CommandLine& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two command-line arguments have the same value if // and only if they are both parsed successfully and have the same // command-line specifications and the same values for flags, options, and // non-option arguments. Note that two identical copies built with the // same option table, but unparsed, are *not* equal. bool operator!=(const CommandLine& lhs, const CommandLine& rhs); // Return 'false' if the specified 'lhs' and 'rhs' have the same value, and // 'true' otherwise. Two command-line arguments do not have the same value // if and only if they have different command-line specifications, or one // is parsed successfully but the other is not, or neither is, or else both // have the same specification and both are parsed successfully but they // have different values for at least one flag, option or non-option // argument. Note that two identical copies built with the same option // table, but unparsed, are *not* equal. bsl::ostream& operator<<(bsl::ostream& stream, const CommandLine& rhs); // Write the options and their values in the specified 'rhs' to the // specified output 'stream' in a (multi-line) human readable format and // return a reference to 'stream'. Note that the last line is *not* // terminated by a newline character. // ============================== // class CommandLineOptionsHandle // ============================== class CommandLineOptionsHandle { // This class provides access to the parsed options (if any) of its // creating 'CommandLine' object. The behavior is undefined if any of the // methods of this class (accessors all) are invoked after a subsequent // invocation of the 'parse' method of the creating object or after the // destruction of the creating object. // PRIVATE TYPES typedef bsl::vector<CommandLine_SchemaData> CommandLine_Schema; typedef bsl::vector<OptionValue> OptionValueList; // DATA const OptionValueList *d_data_p; const CommandLine_Schema *d_schema_p; // FRIENDS friend class CommandLine; friend bool operator==(const CommandLineOptionsHandle&, const CommandLineOptionsHandle&); friend bool operator!=(const CommandLineOptionsHandle&, const CommandLineOptionsHandle&); // PRIVATE CREATORS CommandLineOptionsHandle(const OptionValueList *dataPtr, const CommandLine_Schema *schemaPtr); // Create a 'CommandLineOptionsHandle' object referring to the // specified 'dataPtr' and 'schemaPtr'. The behavior is undefined // unless 'dataPtr->size() == schemaPtr->size()'. public: // ACCESSORS int index(const bsl::string_view& name) const; // Return the position in this handle object of the option having the // specified 'name', and -1 if the handle has no option of that name. // Note that, on success, the return values are in the range // '[0 .. numOptions() - 1]'. const char *name(bsl::size_t index) const; // Return the name of the option at the specified 'index'. The // behavior is undefined unless 'index < numOptions()'. bsl::size_t numOptions() const; // Return the number of parsed options. OptionType::Enum type(bsl::size_t index) const; // Return the type of the option at the specified 'index' in this // handle object. The behavior is undefined unless // 'index < numOptions()'. OptionType::Enum type(const bsl::string_view& name) const; // Return the type of the option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'). const OptionValue& value(bsl::size_t index) const; // Return a 'const' reference to the value (possibly in a null state) // of the option at the specified 'index' in this handle object. The // behavior is undefined unless 'index < numOptions()'. const OptionValue& value(const bsl::string_view& name) const; // Return a 'const' reference to the value (possibly in a null state) // of this handle object's option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'). // 'the*' Accessors // BDE_VERIFY pragma: -FABC01 // not in alphabetic order template <class TYPE> const TYPE& the(bsl::size_t index) const; // Return a 'const' reference to the value of the option at the // specified 'index'. Template parameter 'TYPE' must be one of the // supported types (see {Supported Types}). The behavior is undefined // unless 'index < numOptions()', the option has the (template // parameter) 'TYPE' (i.e., // 'OptionType::TypeToEnum<TYPE>::value == type(index)'), and the // option has a value (i.e., 'false == value(index).isNull()'). template <class TYPE> const TYPE& the(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. Template parameter 'TYPE' must be one of the // supported types (see {Supported Types}). The behavior is undefined // unless this handle object has a 'name' option (i.e., // '0 <= index(name)'), the option has (template parameter) 'TYPE' // (i.e., 'OptionType::TypeToEnum<TYPE>::value == type(name)'), and the // option has a value (i.e., 'false == value(name).isNull()'). bool theBool(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'), the option has type 'bool' (i.e., // 'OptionType::e_BOOL == type(name)'), and the option has a value // (i.e., 'false == value(name).isNull()'). char theChar(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'), the option has type 'char' (i.e., // 'OptionType::e_CHAR == type(name)'), and the option has a value // (i.e., 'false == value(name).isNull()'). int theInt(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'), the option has type 'int' (i.e., // 'OptionType::e_INT == type(name)'), and the option has a value // (i.e., 'false == value(name).isNull()'). bsls::Types::Int64 theInt64(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'), the option has type 'bsls::Types::Int64' // (i.e., 'OptionType::e_INT64 == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). double theDouble(const bsl::string_view& name) const; // Return the value of the option having the specified 'name'. The // behavior is undefined unless this handle object has a 'name' option // (i.e., '0 <= index(name)'), the option has type 'double' (i.e., // 'OptionType::e_DOUBLE == type(name)'), and the option has a value // (i.e., 'false == value(name).isNull()'). const bsl::string& theString(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::string' (i.e., 'OptionType::e_STRING == type(name)'), // and the option has a value (i.e., 'false == value(name).isNull()'). const bdlt::Datetime& theDatetime(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bdlt::Datetime' (i.e., // 'OptionType::e_DATETIME == type(name)'), and the option has a value // (i.e., 'false == value(name).isNull()'). const bdlt::Date& theDate(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bdlt::Date' (i.e., 'OptionType::e_DATE == type(name)'), // and the option has a value (i.e., 'false == value(name).isNull()'). const bdlt::Time& theTime(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bdlt::Time' (i.e., 'OptionType::e_TIME == type(name)'), // and the option has a value (i.e., 'false == value(name).isNull()'). const bsl::vector<char>& theCharArray(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<char>' (i.e., // 'OptionType::e_CHAR_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). const bsl::vector<int>& theIntArray(const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<int>' (i.e., // 'OptionType::e_INT_ARRAY == type(name)'), and the option has a value // (i.e., 'false == value(name).isNull()'). const bsl::vector<bsls::Types::Int64>& theInt64Array( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<bsls::Types::Int64>' (i.e., // 'OptionType::e_INT64_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). const bsl::vector<double>& theDoubleArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<double>' (i.e., // 'OptionType::e_DOUBLE_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). const bsl::vector<bsl::string>& theStringArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<bsl::string>' (i.e., // 'OptionType::e_STRING_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). const bsl::vector<bdlt::Datetime>& theDatetimeArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<bdlt::Datetime>' (i.e., // 'OptionType::e_DATETIME_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). const bsl::vector<bdlt::Date>& theDateArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<bdlt::Date>' (i.e., // 'OptionType::e_DATE_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). const bsl::vector<bdlt::Time>& theTimeArray( const bsl::string_view& name) const; // Return a 'const' reference to the value of the option having the // specified 'name'. The behavior is undefined unless this handle // object has a 'name' option (i.e., '0 <= index(name)'), the option // has type 'bsl::vector<bdlt::TIME>' (i.e., // 'OptionType::e_TIME_ARRAY == type(name)'), and the option has a // value (i.e., 'false == value(name).isNull()'). // BDE_VERIFY pragma: +FABC01 // not in alphabetic order }; // FREE OPERATORS bool operator==(const CommandLineOptionsHandle& lhs, const CommandLineOptionsHandle& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'CommandLineOptionsHandle' objects have the same // value if they have the same 'numOptions' and each of those options have // the same 'name', 'type', and 'value' or are in the null state. bool operator!=(const CommandLineOptionsHandle& lhs, const CommandLineOptionsHandle& rhs); // Return 'true' if the specified 'lhs' and 'rhs' do not have the same // value, and 'false' otherwise. Two 'CommandLineOptionsHandle' objects do // not have the same value if they do not have the same 'numOptions' or if // any of their options differ in 'name', 'type', or 'value (or null // state). // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ----------------------------- // struct CommandLine_SchemaData // ----------------------------- } // close package namespace // FREE OPERATORS inline bool balcl::operator==(const CommandLine_SchemaData& lhs, const CommandLine_SchemaData& rhs) { return lhs.d_type == rhs.d_type && 0 == bsl::strcmp(lhs.d_name_p, rhs.d_name_p); } inline bool balcl::operator!=(const CommandLine_SchemaData& lhs, const CommandLine_SchemaData& rhs) { return lhs.d_type != rhs.d_type || 0 != bsl::strcmp(lhs.d_name_p, rhs.d_name_p); } namespace balcl { // ----------------- // class CommandLine // ----------------- // CLASS METHODS template <int LENGTH> inline bool CommandLine::isValidOptionSpecificationTable( const OptionInfo (&specTable)[LENGTH]) { return isValidOptionSpecificationTable(specTable, LENGTH); } template <int LENGTH> inline bool CommandLine::isValidOptionSpecificationTable( OptionInfo (&specTable)[LENGTH]) { return isValidOptionSpecificationTable(specTable, LENGTH); } template <int LENGTH> inline bool CommandLine::isValidOptionSpecificationTable( const OptionInfo (&specTable)[LENGTH], bsl::ostream& stream) { return isValidOptionSpecificationTable(specTable, LENGTH, stream); } template <int LENGTH> inline bool CommandLine::isValidOptionSpecificationTable( OptionInfo (&specTable)[LENGTH], bsl::ostream& stream) { return isValidOptionSpecificationTable(specTable, LENGTH, stream); } inline bool CommandLine::isValidOptionSpecificationTable(const OptionInfo *specTable, int length) { BSLS_ASSERT(specTable); BSLS_ASSERT(0 <= length); bsl::ostringstream oss; return isValidOptionSpecificationTable(specTable, length, oss); } // CREATORS template <int LENGTH> CommandLine::CommandLine(const OptionInfo (&specTable)[LENGTH], bsl::ostream& stream, bslma::Allocator *basicAllocator) : d_options(basicAllocator) , d_positions(basicAllocator) , d_nonOptionIndices(basicAllocator) , d_state(e_INVALID) , d_arguments(basicAllocator) , d_schema(basicAllocator) , d_data(basicAllocator) , d_data1(basicAllocator) , d_data2(basicAllocator) , d_isBindin2Valid(false) { for (int i = 0; i < LENGTH; ++i) { d_options.push_back(Option(specTable[i])); } validateAndInitialize(stream); d_state = e_NOT_PARSED; } template <int LENGTH> CommandLine::CommandLine(OptionInfo (&specTable)[LENGTH], bsl::ostream& stream, bslma::Allocator *basicAllocator) : d_options(basicAllocator) , d_positions(basicAllocator) , d_nonOptionIndices(basicAllocator) , d_state(e_INVALID) , d_arguments(basicAllocator) , d_schema(basicAllocator) , d_data(basicAllocator) , d_data1(basicAllocator) , d_data2(basicAllocator) , d_isBindin2Valid(false) { for (int i = 0; i < LENGTH; ++i) { d_options.push_back(Option(specTable[i])); } validateAndInitialize(stream); d_state = e_NOT_PARSED; } template <int LENGTH> CommandLine::CommandLine(const OptionInfo (&specTable)[LENGTH], bslma::Allocator *basicAllocator) : d_options(basicAllocator) , d_positions(basicAllocator) , d_nonOptionIndices(basicAllocator) , d_state(e_INVALID) , d_arguments(basicAllocator) , d_schema(basicAllocator) , d_data(basicAllocator) , d_data1(basicAllocator) , d_data2(basicAllocator) , d_isBindin2Valid(false) { for (int i = 0; i < LENGTH; ++i) { d_options.push_back(Option(specTable[i])); } validateAndInitialize(); d_state = e_NOT_PARSED; } template <int LENGTH> CommandLine::CommandLine(OptionInfo (&specTable)[LENGTH], bslma::Allocator *basicAllocator) : d_options(basicAllocator) , d_positions(basicAllocator) , d_nonOptionIndices(basicAllocator) , d_state(e_INVALID) , d_arguments(basicAllocator) , d_schema(basicAllocator) , d_data(basicAllocator) , d_data1(basicAllocator) , d_data2(basicAllocator) , d_isBindin2Valid(false) { for (int i = 0; i < LENGTH; ++i) { d_options.push_back(Option(specTable[i])); } validateAndInitialize(); d_state = e_NOT_PARSED; } // ------------------------------ // class CommandLineOptionsHandle // ------------------------------ // PRIVATE CREATORS inline CommandLineOptionsHandle::CommandLineOptionsHandle( const OptionValueList *dataPtr, const CommandLine_Schema *schemaPtr) : d_data_p(dataPtr) , d_schema_p(schemaPtr) { BSLS_ASSERT(dataPtr); BSLS_ASSERT(schemaPtr); BSLS_ASSERT(dataPtr->size() == schemaPtr->size()); } // ACCESSORS inline const char *CommandLineOptionsHandle::name(bsl::size_t index) const { BSLS_ASSERT(index < d_schema_p->size()); return (*d_schema_p)[index].d_name_p; } inline bsl::size_t CommandLineOptionsHandle::numOptions() const { return d_schema_p->size(); } inline OptionType::Enum CommandLineOptionsHandle::type(bsl::size_t index) const { BSLS_ASSERT(index < d_schema_p->size()); return (*d_schema_p)[index].d_type; } inline OptionType::Enum CommandLineOptionsHandle::type( const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(static_cast<bsl::size_t>(index) < d_schema_p->size()); return (*d_schema_p)[index].d_type; } inline const OptionValue& CommandLineOptionsHandle::value(bsl::size_t index) const { BSLS_ASSERT(index < d_schema_p->size()); return (*d_data_p)[index]; } inline const OptionValue& CommandLineOptionsHandle::value( const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(static_cast<bsl::size_t>(index) < d_schema_p->size()); return (*d_data_p)[index]; } // 'the*' Accessors // BDE_VERIFY pragma: -FABC01 // not in alphabetic order template <class TYPE> const TYPE& CommandLineOptionsHandle::the(bsl::size_t index) const { BSLS_ASSERT(OptionType::TypeToEnum<TYPE>::value == type(index)); BSLS_ASSERT(!value(index).isNull()); return (*d_data_p)[index].the<TYPE>(); } template <class TYPE> const TYPE& CommandLineOptionsHandle::the(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::TypeToEnum<TYPE>::value == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<TYPE>(index); } inline bool CommandLineOptionsHandle::theBool(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_BOOL == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Bool>(index); } inline char CommandLineOptionsHandle::theChar(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_CHAR == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Char>(index); } inline int CommandLineOptionsHandle::theInt(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_INT == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Int>(index); } inline bsls::Types::Int64 CommandLineOptionsHandle::theInt64( const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_INT64 == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Int64>(index); } inline double CommandLineOptionsHandle::theDouble(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_DOUBLE == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Double>(index); } inline const bsl::string& CommandLineOptionsHandle::theString(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_STRING == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::String>(index); } inline const bdlt::Datetime& CommandLineOptionsHandle::theDatetime(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_DATETIME == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Datetime>(index); } inline const bdlt::Date& CommandLineOptionsHandle::theDate(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_DATE == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Date>(index); } inline const bdlt::Time& CommandLineOptionsHandle::theTime( const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_TIME == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Time>(index); } inline const bsl::vector<char>& CommandLineOptionsHandle::theCharArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_CHAR_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::CharArray>(index); } inline const bsl::vector<int>& CommandLineOptionsHandle::theIntArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_INT_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::IntArray>(index); } inline const bsl::vector<bsls::Types::Int64>& CommandLineOptionsHandle::theInt64Array(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_INT64_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::Int64Array>(index); } inline const bsl::vector<double>& CommandLineOptionsHandle::theDoubleArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_DOUBLE_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::DoubleArray>(index); } inline const bsl::vector<bsl::string>& CommandLineOptionsHandle::theStringArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_STRING_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::StringArray>(index); } inline const bsl::vector<bdlt::Datetime>& CommandLineOptionsHandle::theDatetimeArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_DATETIME_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::DatetimeArray>(index); } inline const bsl::vector<bdlt::Date>& CommandLineOptionsHandle::theDateArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_DATE_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::DateArray>(index); } inline const bsl::vector<bdlt::Time>& CommandLineOptionsHandle::theTimeArray(const bsl::string_view& name) const { int index = this->index(name); BSLS_ASSERT(0 <= index); BSLS_ASSERT(OptionType::e_TIME_ARRAY == type(index)); BSLS_ASSERT(!value(index).isNull()); return the<OptionType::TimeArray>(index); } // BDE_VERIFY pragma: +FABC01 // not in alphabetic order } // close package namespace // FREE OPERATORS inline bool balcl::operator==(const balcl::CommandLineOptionsHandle& lhs, const balcl::CommandLineOptionsHandle& rhs) { BSLS_ASSERT(lhs.d_data_p); BSLS_ASSERT(lhs.d_schema_p); BSLS_ASSERT(rhs.d_data_p); BSLS_ASSERT(rhs.d_schema_p); return *lhs.d_data_p == *rhs.d_data_p && *lhs.d_schema_p == *rhs.d_schema_p; } inline bool balcl::operator!=(const balcl::CommandLineOptionsHandle& lhs, const balcl::CommandLineOptionsHandle& rhs) { BSLS_ASSERT(lhs.d_data_p); BSLS_ASSERT(lhs.d_schema_p); BSLS_ASSERT(rhs.d_data_p); BSLS_ASSERT(rhs.d_schema_p); return *lhs.d_data_p != *rhs.d_data_p || *lhs.d_schema_p != *rhs.d_schema_p; } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2020 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------