BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balcl_commandline

Detailed Description

Outline

Purpose

Provide command line parsing, validation, and access.

Classes

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, an optionally-used class that provides an alternate means of 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.

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.
  8. The ability to specify option values through environment variables.
  9. The ability to specify defaults for options, to be used when options are not specified on the command line or through environment variables.

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:

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 character; 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.

Setting Options via Environment Variables

Sometimes users may wish to supply configuration via environment variables, which is common practice, for example, for services deployed via Docker containers in cloud environments.

By default, parsed command line option values are unaffected by the environment. If an environment variable name is specified for an option, then, during parsing, if an option is not set on the command line, and the specified environment variable has a value, that value is used for the command line option. If a value is not supplied, either via the command line, or via an environment variable, then the default value for the option, if any, is used.

Setting Boolean Options via Environment Variables

Boolean options when set via the environment variable must be associated with a string.

+---------------+--------------+
| desired value | valid text |
+---------------+--------------+
| true | "true", "1" |
| false | "false", "0" |
+---------------+--------------+

Any other text, including an empty string, is treated as invalid input.

Setting Array Options via Environement Variables

Array options can be set by environment variable. When an array option is supplied via an environment variable string, the discrete values must be separated using the space character. For example, if the program takes an integer array of years as an option, and that option is associated with the environment variable name "MYPROG_YEARS", to supply a value via the command line one could specify:

$ export MYPROG_YEARS="2010 2014 2018 2022"

The '\' is used as an escape-character if an element of an array contains a space. For example:

$ export MYPROG_WINPATH='C:\\Program\ Files\\MyProg D:\\Another\\Path'

would configure an array containing "C:\Program Files\MyProg" and "D:\Another\Path".

Best Practices for Environment Variable Naming

Environment variable exist in a single namespace accessed by all programs run in the shell, and many environment variable names are used by many different systems for different purposes. For that reason, we strongly encourage selecting a (ideally) unique prefix for the environment variables used by your application, to reduce the likelihood of collisions with environment variables used by other applications for different purposes.

For example, if someone were writing a trading application tradesvc, they might choose to use "TRADESVC_" as a common prefix for the environment variables.

Specifying Options

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).
environment variable name Specify an environment variable name that
can be used to set the option.

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 -, but not as the first character, and 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.

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::Option. 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 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:

/// 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(&variable)
balcl::TypeInfo(&variable, 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 @ref balcl_optiontype-enumerators .
balcl::TypeInfo(type, constraint)
Definition balcl_typeinfo.h:117

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:

a default value
@ e_REQUIRED
Definition balcl_occurrenceinfo.h:130
@ e_OPTIONAL
Definition balcl_occurrenceinfo.h:131
@ e_HIDDEN
Definition balcl_occurrenceinfo.h:132

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.

Environment Variable Name Field

The environment variable name field is used to specify a string which is the name of an environment variable which, if set, allows the environment to be searched for a value of the option. If an option is specified on the command line, the environment is never searched for that option. If an option has a default value, and a value is specified in the environment, the value in the environment takes precedence over the default value.

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
Definition bslstl_vector.h:1025

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. Since there is no
linked variable, the value of the option must be obtained
using the field name passed to the 'the<TYPE>' accessor
(in this case 'theInt').
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.
This option value consists of a sequence of string
values specified on the command line, in the same order.
static StringArray *const k_STRING_ARRAY
Definition balcl_optiontype.h:305
static Int *const k_INT
Definition balcl_optiontype.h:294
static Bool *const k_BOOL
Definition balcl_optiontype.h:292

Example: Occurrence Information Field

The following values may be used for this field:

Usage Meaning
=============== ========================================================
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 or through an environment variable, isSpecified will will return false andnumSpecified' will return 0. If no default value is provided and if the variable is a linked variable, it will be unmodified by the parsing. If the variable is accessed through CommandLineOptionsHandle::value, it will be in a null state (defined type but no defined value).

Example: Environment Variable Name Field

The name field may be declared using the following form:

Usage Meaning
=============== =======================================================
"MYPROG_XYZ" The option can be set by "export MYPROG_XYZ=<value>"

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
Definition bdlt_date.h:294
Definition bdlt_datetime.h:331
Definition bdlt_time.h:196
Definition bslstl_string.h:1281
long long Int64
Definition bsls_types.h:132

The ASCII representation of these values (i.e., the actual format of the values on command lines) depends on the type:

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.

TagNameDescription Fields

The tag, name, and description fields must pass the isTagValid, isNameValid, andisDescriptionValid' methods of balcl::Option, respectively.

Collectively, each non-empty short tag, each long tag, and each name must be unique in the specification.

Default Values

Non-Option Arguments

Boolean Options (Flags)

Options having the bool type (also known as "flags") are distinguished from the other supported option types in several ways:

Usage

This section illustrates intended use of this component.

Example 1: Parsing Command Line Options Using Minimal Functionality

Suppose we want to design a sorting utility named mysort that has the following syntax:

Usage: mysort [-r|reverse] [-f|field-separator <fieldSeparator>]
-o|outputfile <outputFile> [<fileList>]+
// Sort the specified files (in 'fileList'), and
// write the output to the specified output file.

The <fileList> argument is a non-option, meaning that its value or values appear on the command line unannounced by tags. In this case, the + following the argument means that it is an array type of argument where at least one element is required, so its values are stored in a bsl::vector.

int main(int argc, const char **argv)
{
Definition balcl_occurrenceinfo.h:120

First, we define our variables to be initialized from the command line. All values must be initialized to their default state:

bool reverse = false;
bsl::string outputFile;
char fieldSeparator = '|';

Then, we define our OptionInfo table of attributes to be set. The fields of the OptionInfo are:

Finally, we show what will happen if mysort is called with invalid arguments. We will call without specifying an input file to fileList, which will be an error. parse streams a message describing the error and then returns non-zero, so our program will call cmdLine.printUsage, which prints a detailed usage message.

$ mysort -r -o sorted.txt
Error: No value supplied for the non-option argument "fileList".
Usage: mysort [-r|reverse] [-f|field-separator <fieldSeparator>]
-o|outputfile <outputFile> [<fileList>]+
Where:
-r | --reverse
sort in reverse order
-f | --field-separator <fieldSeparator>
field separator character
-o | --outputfile <outputFile>
output file
<fileList>
input files to be sorted

Example 2: Accessing Option Values Through balcl::CommandLine Accessors

Imagine we defined the same mysort program with the same options. After a successful parse, balcl::Commandline makes the state of every option available through accessors (in addition to setting external variables as shown in example 1).

For every type that is supported, there is a the<TYPE> accessor which takes a single argument, the name of the argument. In the above program, if parsing was successful, the following asserts will always pass:

assert(cmdLine.theBool("isReverse") == reverse);
assert(cmdLine.theString("outputFile") == outputFile);
assert(cmdLine.theStringArray("fileList") == files);

The next accessors we'll discuss are isSpecified and numSpecified. Here, we use isSpecified to determine whether "fieldSeparator" was specified on the command line, and we use numSpecified to determine the number of times the "fieldSeparator" option appeared on the command line:

if (cmdLine.isSpecified("fieldSeparator")) {
const unsigned char uc = cmdLine.theChar("fieldSeparator");
if (!::isprint(uc)) {
bsl::cerr << "'fieldSeparator' must be printable.\n";
return -1; // RETURN
}
}
if (1 < cmdLine.numSpecified("fieldSeparator")) {
bsl::cerr <<
"'fieldSeparator' may not be specified more than once.\n";
return -1; // RETURN
}

Example 3: Default Values and Specifying Values Via The Environment

Suppose we are implementing mysort (from examples 1 & 2) again, but here we want to make use of default option values and the ability to supply options via the environment.

In this example, we have decided not to link local variables, and instead access the option values via the balcl::CommandLine object. Since we are not linking local variables, we specify OptionType::k_<TYPE> in the specification table below for each TypeInfo field.

To specify default values, we pass the default value to the OccurrenceInfo field. Boolean options always have a default value of false.

We also choose to allow these options to be supplied through the environment. To enable this, we specify an environment variable name as the 5th (optional) element of the OptionInfo specification for the option. If no name is supplied for the environment variable, the option cannot be set via the environment.

First, in main, we define our spec table:

// option specification table
static const balcl::OptionInfo specTable[] = {
{
"r|reverse", // tag
"isReverse", // name
"sort in reverse order", // description
TypeInfo(OptionType::k_BOOL), // type
OccurrenceInfo::e_OPTIONAL, // optional
"MYSORT_REVERSE" // env var name
},
{
"", // non-option
"fileList", // name
"input files to be sorted", // description
TypeInfo(OptionType::k_STRING_ARRAY), // type
OccurrenceInfo::e_REQUIRED, // at least one file required
"MYSORT_FILES" // env var name
}
};
int main(int argc, const char **argv)
{
Definition balcl_optiontype.h:224

Then, we declare our cmdLine object. This time, we pass it a stream, and messages will be written to that stream rather than cerr (the default).

balcl::CommandLine cmdLine(specTable, bsl::cout);

Next, we call parse (just like in Example 1):

if (cmdLine.parse(argc, argv)) {
cmdLine.printUsage();
return -1; // RETURN
}

balcl::CommandLine uses the following precedence to determine the value of a command line option:

  1. Use the option value on the command-line (if one was supplied)
  2. Use the option value supplied by an environment variable (if one was supplied)
  3. Use the default value (if one was supplied, or false for booleans)

Finally, if an option value is not supplied by either the command line or environment, and there is no default value, any linked variable will be unmodified, cmdLine.hasValue for the option will return false, and the behavior is undefined if cmdLine.the<TYPE> for the option is called.

Note that cmdLine.isSpecified will be true only if an option was supplied by the command line or the environment.

If an array options is set by an environment variable, the different elements of the array are separated by spaces by default.

All these calling sequences are equivalent:

$ mysort -r inputFile1 inputFile2 inputFile3

or

$ mysort inputFile1 --reverse inputFile2 inputFile3

or

$ mysort inputFile1 inputFile2 inputFile3 -r

or the user can specify arguments through environment variables:

$ export MYSORT_REVERSE=true
$ export MYSORT_FILES="inputFile1 inputFile2 inputFile3"
$ mysort

or as a combination of command line arguments and environment variables:

$ export MYSORT_FILES="inputFile1 inputFile2 inputFile3"
$ mysort -r

The '\' character is used as an escape character for array values provided via an environment variable. So, for example, if we needed to encode file names that contain a space (), which is the element separator (by default), we would use "\ ":

$ export MYSORT_FILES='C:\\file\ name\ 1 C:\\file\ name\ 2'

Notice we used a single tick to avoid requiring a double escape when supplying the string to the shell (e.g., avoiding "C:\\\\file\\ name\\ 1").

Example 4: Option Constraints

Suppose, we are again implementing mysort, and we want to introduce some constraints on the values supplied for the variables. In this example, we will ensure that the supplied input files exist and are not directories, and that fieldSeparator is appropriate.

First, we write a validation function for the file name. A validation function supplied to balcl::CommandLine takes an argument of a const pointer to the input option type (with the user provided value) and a stream on which to write an error message, and the validation function returns a bool that is true if the option is valid, and false otherwise.

Here, we implement a function to validate a file name, that returns true if the file exists and is a regular file, and false otherwise (writing an description of the error to the stream):

bool isValidFileName(const bsl::string *fileName, bsl::ostream& stream)
{
if (!bdls::FilesystemUtil::isRegularFile(*fileName, true)) {
stream << "Invalid file: " << *fileName << bsl::endl;
return false; // RETURN
}
return true;
}
static bool isRegularFile(const char *path, bool followLinksFlag=false)

Then, we also want to make sure that the specified fieldSeparator is a non-whitespace printable ascii character, so we write a function for that:

bool isValidFieldSeparator(const char *fieldSeparator,
bsl::ostream& stream)
{
const unsigned char uc = *fieldSeparator;
if (::isspace(uc) || !::isprint(uc)) {
stream << "Invalid field separator specified." << bsl::endl;
return false; // RETURN
}
return true;
}

Next, we define main and declare the variables to be configured:

int main(int argc, const char **argv)
{
bool reverse = false;
char fieldSeparator;
Definition balcl_constraint.h:89

Notice that fieldSeparator are in automatic storage with no constructor or initial value. We can safely use an uninitialized variable in the specTable below because the specTable provides a default value for it, which will be assigned to the variable if an option value is not provided on the command line or through environment variables. reverse has to be initialized because no default for it is provided in specTable.

Then, we declare our specTable, providing function pointers for our constraint functions to the second argument of the TypeInfo constructor.

// option specification table
static const balcl::OptionInfo specTable[] = {
{
"r|reverse", // tag
"isReverse", // name
"sort in reverse order", // description
TypeInfo(&reverse), // linked variable
OccurrenceInfo(), // default value
"" // env variable name
},
{
"f|field-separator", // tag
"fieldSeparator", // name
"field separator character", // description
TypeInfo(&fieldSeparator, // linked variable
&isValidFieldSeparator), // constraint
OccurrenceInfo('|'),
"" // env variable name
},
{
"", // non-option
"fileList", // name
"input files to be sorted", // description
TypeInfo(&files, &isValidFileName), // linked variable and
// constraint
OccurrenceInfo::e_REQUIRED, // at least one file
// required
"" // env variable name
}
};
balcl::CommandLine cmdLine(specTable);
if (cmdLine.parse(argc, argv)) {
cmdLine.printUsage();
return -1; // RETURN
}

If the constraint functions return false, cmdLine.parse will return non-zero, and the output will contain the message from the constraint function followed by the usage message.

Example 5: Using bsl::optional for Optional Command Line Parameters

We can use a bsl::optional variables when providing optional command line parameters. Suppose we want to write a command line that takes an optional input file, and if the file is not supplied, take input from a bsl::stringstream.

To represent the optional file name parameter, we link a variable of type bsl::optional<bsl::string>. In general, when linking a variable to an option, we can choose to use bsl::optonal<TYPE> in place of TYPE, for any option type other than bool.

int main(int argc, const char **argv)
{
bsl::optional<bsl::string> optionalFileName;
const balcl::OptionInfo specTable[] = {
{
"i|inputFile", // tag
"filename", // name
"name of input file", // description
balcl::TypeInfo(&optionalFileName), // linked optional variable
balcl::OccurrenceInfo(), // occurence info
"" // env variable name
}
};
balcl::CommandLine cmdLine(specTable);
if (cmdLine.parse(argc, argv)) {
cmdLine.printUsage();
return -1; // RETURN
}
Definition bslstl_optional.h:1861

Finally, we test whether optionalFileName has been set, and if it has not been set, take input from a prepared stringstream.

bsl::istream *inStream = &ss;
bsl::ifstream fileStream;
if (optionalFileName.has_value()) {
fileStream.open(optionalFileName->c_str());
inStream = &fileStream;
}
else {
// Prepare the 'stringstream'.
ss << "The quick brown fox jumps over the lazy dog\n";
}
performTask(*inStream);
Definition bslstl_stringstream.h:184