2.6.0
Freundlich's C++ toolkit
Classes | Typedefs | Functions
fcppt.options

Description

Library for command-line options.

Introduction

In C++, the main function receives an array of strings in the form of (int argc, char **argv), which is most of the time not immediately usable in a program. Consider a program that expects a single integer argument. We not only have to check if argc has the right value but we also have to convert the first string into an integer. Although this example is as simple as it can get, using argc and argv directly is already difficult. In more complicated examples that involve optional arguments, flags, or even arbitrary many arguments, this process gets even more error-prone.

fcppt.options features declarative parsers that carry attributes of the right type, similar to optparse-applicative in Haskell, though here the attribute of a parser is always an fcppt::record::object, so that accessing individual parts is done by labels in order to make their purpose clearer. For example, a parser that expects a single integer with label name age has type { age : int }. Parsers can be combined to yield more complicated parsers, so for example a parser that expects zero or more strings with label name first_names has type { first_names : std::vector<std::string> }. Combining these two parsers yields { age : int, first_names : std::vector<std::string> }.

A simple example

To start off, let us look at a simple example that expects a single argument of type int. First, we need to declare the label that is being used:

age_label
);

Next, we declare the parser type that uses age_label to produce a single value of type int.

typedef
age_label,
int
>
parser_type;
typedef
parser_type
>
result_type;

Such a parser parses a command-line like ./program "123", yielding the record { age_label = 123 }, which is of type result_type = { age_label : int }. Next, we define the actual parser:

parser_type const parser{
FCPPT_TEXT("age")
},
FCPPT_TEXT("Your age")
}
}
};

Here, we see that an fcppt::options::argument gets two parameters:

As you can see, the long name is mandatory, while the help text is optional.

Instead of using argc and argv directly, we first use the helper function fcppt::args_from_second which copies every argument except the first (which usually hold's the program's name but isn't required to) into a container:

argc,
argv
)
);

Parsing the arguments using a parser is done by calling the fcppt::options::parse function. Its result is an fcppt::options::result which is an fcppt::either::object that encapsulates the fact that a parser can fail.

result_type
> const result{
parser,
)
};

Now, all that needs to be done is to inspect result: First, we define a function called on_success that receives result_type (remember, this is a record of type { age_label : int }) and prints it.

auto const on_success(
[](
result_type const &_result
)
{
<<
FCPPT_TEXT("Your age is ")
<<
age_label
>(
_result
)
<<
FCPPT_TEXT('\n');
return
EXIT_SUCCESS;
}
);

In case of failure we get an fcppt::options::error, containing a message of what went wrong. In addition to that, we also print parser.usage() which tells the user what the expected format is:

auto const on_failure(
[
&parser
](
fcppt::options::error const &_error
)
{
<<
_error
<<
FCPPT_TEXT('\n')
<<
FCPPT_TEXT("Usage: ")
<<
parser.usage()
<<
FCPPT_TEXT('\n');
return
EXIT_FAILURE;
}
);

Finally, we use fcppt::either::match to call one of these functions:

return
result,
on_failure,
on_success
);

Parser types

Parser types are split into basic and combinator parsers.

Basic parser types

There are three different types of basic parsers:

Type: Description:
fcppt::options::argument Parses a single argument, e.g. "arg". If there is no argument or it cannot be converted to the parser's result type, an error occurs.
fcppt::options::flag Parses a flag, e.g. "-f" or "--flag". Depending on whether the flag was specified or not, the result type is either its inactive value or its active value. Flags never produce an error.
fcppt::options::option Parses an option, e.g. "-o val" or "--opt val". Option parsers can have an optional default value which is used in case the option has not been specified. If there is no such option and no default value has been specified or the option's value cannot be converted to the parser's result type, an error occurs.

As a shortcut, fcppt::options::switch_ is a short-hand for a flag of type bool.

Combinator parser types

The following parsers can be used to create more advanced parsers:

Type: Description:
fcppt::options::product A parser of type fcppt::options::product<Left,Right> combines two parsers of type Left and Right, which must have disjoint records. The product parser first tries the left parser and then the right parser. It only succeeds if both succeed. Its result type is the disjoint union (see fcppt::record::multiply_disjoint) of Left's and Right's result types. To combine two or more parsers at once, use fcppt::options::apply.
fcppt::options::optional A parser of type fcppt::options::optional<Parser> turns a parser of type Parser into a parser that may fail. Its result type has the same labels as Parser's result type, but with an extra fcppt::optional::object layer added on top. See fcppt::options::make_optional.
fcppt::options::many A parser of type fcppt::options::many<Parser> turns a parser of type Parser into a parser that parsers zero or more occurrences. Its result type has the same labels as Parser's result type, but with an extra std::vector layer added on top. See fcppt::options::make_many.

A more complex example

Imagine a program that copies an input file to an output file, but with some additional twists:

We first start by declaring the labels the parsers are going to use:

input_file_label
);
output_file_label
);
execute_label
);
openmode_label
);
log_level_label
);

The input filename is an argument parser of type fcppt::string.

typedef
input_file_label,
>
input_file_option;
input_file_option const input_file{
FCPPT_TEXT("Input filename")
},
FCPPT_TEXT("The name of the input file to copy")
}
}
};

The output filename is an optional argument parser. Its type is fcppt::optional::object<fcppt::string>.

typedef
output_file_label,
>
output_file_option;
typedef
output_file_option
>
optional_output_file_option;
optional_output_file_option const output_file{
output_file_option{
FCPPT_TEXT("Output filename")
},
FCPPT_TEXT("The name of the output file. Defaults to input_file.bak")
}
}
}
)
};

The execute flag is just a switch. It can be activated using "-e" or "--execute".

typedef
execute_label
>
execute_switch;
execute_switch const execute{
}
},
FCPPT_TEXT("execute")
},
FCPPT_TEXT("Whether to actually execute the actions")
}
}
};

To handle whether to append to the output file, we use a flag parser of type std::ios_base::openmode. Its inactive value is the empty openmode, while its active value is std::ios_base::trunc.

typedef
openmode_label,
std::ios_base::openmode
>
openmode_option;
openmode_option const openmode{
FCPPT_TEXT("trunc")
},
std::ios_base::trunc
},
std::ios_base::openmode{}
},
FCPPT_TEXT("Whether to truncate the output file")
}
}
};

The log level is an option parser of type fcppt::log::level. It can be set using "-l level" or "--loglevel level", where level has to be one of fcppt::log::level's values. The parser also gets a default value of fcppt::log::level::warning.

typedef
log_level_label,
>
log_level_option;
log_level_option const log_level{
}
},
FCPPT_TEXT("loglevel")
},
log_level_option::optional_default_value{
)
},
FCPPT_TEXT("The log level to use")
}
}
};

Finally, the actual parser is created using fcppt::options::apply. Its type is complicated, so it is shortened using auto here. See Hiding parser implementation on how to hide a parser's actual type.

auto const parser(
input_file,
output_file,
execute,
openmode,
log_level
)
);
typedef
decltype(
parser
)
>
result_type;

The main program is a lambda function that gets result_type as its parameter. This is a record that contains all the options of the parsers combined.

auto const main_program(
[](
result_type const &_result
)
-> bool
{

First, we check if the execute flag has been specified. If not, the executing stops.

if(
execute_label
>(
_result
)
)
return
false;

Next, we create a log context that uses the log-level specified. Notice how the string specified on the command-line has already been converted to a value of fcppt::log::level.

fcppt::log::context log_context{
log_level_label
>(
_result
)
},
};

We then open the input file using the input filename.

>(
input_file_label
>(
_result
),
std::ios_base::openmode{}
)
};

Opening the output file consists of two things: First, we need to check whether the output filename has been specified. If not, we use the default of input_file.bak.

fcppt::string const output_filename{
output_file_label
>(
_result
),
[
&_result
]{
return
input_file_label
>(
_result
)
+
FCPPT_TEXT(".bak");
}
)
};

Second, the openmode needs to be passed as well.

>(
output_filename,
openmode_label
>(
_result
)
)
};

Help option

A help option is a special flag like "--help". If specified, the program should print its help text and not accept any other arguments. This layering of two parsers is implemented by fcppt::options::parse_help. It gets a parser of type fcppt::options::help_switch as its first argument, and a regular parser as its second argument. fcppt::options::default_help_switch is a switch that accepts "--help":

parser_type
>
> const result{
parser,
argc,
argv
)
)
};

If the help switch matches, the function returns an fcppt::options::help_text, otherwise it returns a regular fcppt::options::result.

result,
[](
parser_type
>
> const &
)
{
// ...
},
[](
fcppt::options::help_text const &_help_text
)
{
<<
_help_text
<<
FCPPT_TEXT('\n');
}
);

Hiding parser implementation

As seen in A more complex example, the type of a parser can get very complex, because it carries the exact types of all the parsers used to build it. In order to hide this, the base class fcppt::options::base can be used. Its only type parameter is the parser's result type, which means that we need to know the result type in advance. In the following example, we are going to expect a parser that returns an int and a bool:

int_arg_label
);
switch_label
);
typedef
int_arg_label,
int
>,
switch_label,
bool
>
>
result_type;

Next, we define a function that creates such a parser. In a real program, this can be hidden away inside another translation unit:

auto const create_base(
[]()
->
result_type
>
{
return
result_type
>(
int_arg_label,
int
>{
FCPPT_TEXT("arg")
},
},
switch_label
>{
FCPPT_TEXT("switch")
},
}
)
);
}
);

The parser can then be used like any other parser:

result_type
> const base{
create_base()
};
result_type
> const result{
*base,
argc,
argv
)
)
};

It is also possible to use such an fcppt::options::base_unique_ptr as an argument to another parser:

auto const combined{
create_base()
)
};

Classes

struct  fcppt::options::active_value_tag
 The tag of strong typedefs for active values. More...
 
class  fcppt::options::argument< Label, Type >
 An argument parser. More...
 
class  fcppt::options::base< Result >
 The base class for parsers with a given result type. More...
 
struct  fcppt::options::default_value_tag
 The tag of strong typedefs for default values. More...
 
class  fcppt::options::flag< Label, Type >
 A flag parser. More...
 
struct  fcppt::options::inactive_value_tag
 The tag of strong typedefs for inactive values. More...
 
class  fcppt::options::many< Parser >
 A parser for zero or more elements. More...
 
class  fcppt::options::option< Label, Type >
 An option parser. More...
 
class  fcppt::options::optional< Parser >
 An optional parser. More...
 
class  fcppt::options::product< Left, Right >
 A product of two parsers. More...
 
class  fcppt::options::state
 A parse state. More...
 
class  fcppt::options::switch_< Label >
 A switch parser. More...
 

Typedefs

template<typename Type >
using fcppt::options::active_value = fcppt::strong_typedef< Type, fcppt::options::active_value_tag >
 A strong typedef used as a parser's active value. More...
 
template<typename Result >
using fcppt::options::base_unique_ptr = fcppt::unique_ptr< fcppt::options::base< Result > >
 A unique pointer for fcppt::options::base. More...
 
template<typename Type >
using fcppt::options::default_value = fcppt::strong_typedef< Type, fcppt::options::default_value_tag >
 A strong typedef used as a parser's default value. More...
 
typedef fcppt::variant::variadic< fcppt::options::missing_error, fcppt::options::other_errorfcppt::options::error
 The error type returned by parsers. More...
 
typedef std::unordered_set< fcppt::stringfcppt::options::has_parameter_set
 The set of option names. More...
 
typedef fcppt::options::switch_< fcppt::options::detail::help_label > fcppt::options::help_switch
 The type of a help parser. More...
 
typedef fcppt::strong_typedef< fcppt::string,_ > fcppt::options::help_text
 A string type representing a help text. More...
 
template<typename Type >
using fcppt::options::inactive_value = fcppt::strong_typedef< Type, fcppt::options::inactive_value_tag >
 A strong typedef used as a parser's inactive value. More...
 
typedef fcppt::strong_typedef< fcppt::string,_ > fcppt::options::long_name
 A string type representing a long name. More...
 
typedef fcppt::strong_typedef< fcppt::string,_ > fcppt::options::missing_error
 A string type representing a missing error. More...
 
typedef fcppt::optional::object< fcppt::options::help_textfcppt::options::optional_help_text
 An optional help text. More...
 
typedef fcppt::optional::object< fcppt::options::short_namefcppt::options::optional_short_name
 An optional short name. More...
 
typedef fcppt::strong_typedef< fcppt::string,_ > fcppt::options::other_error
 A string type representing other errors. More...
 
template<typename T >
using fcppt::options::result = fcppt::either::object< fcppt::options::error, T >
 The result of a parse. More...
 
template<typename Parser >
using fcppt::options::result_of = typename fcppt::options::detail::result_of< Parser >::type
 The result of a parser type. More...
 
typedef fcppt::strong_typedef< fcppt::string,_ > fcppt::options::short_name
 A string type representing a short name. More...
 

Functions

template<typename... Parsers>
auto fcppt::options::apply (Parsers &&..._parsers)
 Combines two or more parsers. More...
 
FCPPT_OPTIONS_DETAIL_SYMBOL fcppt::options::help_switch fcppt::options::default_help_switch ()
 The default help switch. More...
 
FCPPT_OPTIONS_DETAIL_SYMBOL bool fcppt::options::is_option (fcppt::string const &)
 Checks if a string is an option. More...
 
template<typename Type >
fcppt::options::active_value< typename std::decay< Type >::type > fcppt::options::make_active_value (Type &&_value)
 Creates an active value. More...
 
template<typename Result , typename Parser >
fcppt::options::base_unique_ptr< Result > fcppt::options::make_base (Parser &&_parser)
 Creates an fcppt::options::base. More...
 
template<typename Type >
fcppt::options::default_value< typename std::decay< Type >::type > fcppt::options::make_default_value (Type &&_value)
 Creates a default value. More...
 
template<typename Type >
fcppt::options::inactive_value< typename std::decay< Type >::type > fcppt::options::make_inactive_value (Type &&_value)
 Creates an inactive value. More...
 
template<typename Parser >
fcppt::options::many< typename std::decay< Parser >::type > fcppt::options::make_many (Parser &&_parser)
 Turns a parser into a many parser. More...
 
template<typename Parser >
fcppt::options::optional< typename std::decay< Parser >::type > fcppt::options::make_optional (Parser &&_parser)
 Turns a parser into an optional parser. More...
 
template<typename Type >
fcppt::options::default_value< fcppt::optional::object< Type >> fcppt::options::no_default_value ()
 Creates an empty default value. More...
 
template<typename Parser >
fcppt::options::result< fcppt::options::result_of< Parser >> fcppt::options::parse (Parser const &_parser, fcppt::args_vector const &_args)
 Parse a command-line. More...
 
template<typename Parser >
fcppt::options::help_result< fcppt::options::result_of< Parser >> fcppt::options::parse_help (fcppt::options::help_switch const &_help, Parser const &_parser, fcppt::args_vector const &_args)
 Parse a command-line with a help parser. More...
 
template<typename Type >
fcppt::string fcppt::options::pretty_type ()
 Returns a pretty type used for help texts. More...
 

Typedef Documentation

◆ active_value

template<typename Type >
using fcppt::options::active_value = typedef fcppt::strong_typedef< Type, fcppt::options::active_value_tag >

A strong typedef used as a parser's active value.

◆ base_unique_ptr

template<typename Result >
using fcppt::options::base_unique_ptr = typedef fcppt::unique_ptr< fcppt::options::base< Result > >

A unique pointer for fcppt::options::base.

Template Parameters
ResultThe result type of the parser. Must be an fcppt::record::object.

◆ default_value

A strong typedef used as a parser's default value.

◆ error

The error type returned by parsers.

An error can either be caused by a missing argument or option, or by something else like a failed conversion.

◆ has_parameter_set

typedef std::unordered_set< fcppt::string> fcppt::options::has_parameter_set

The set of option names.

Each string in this set is expected to be followed by a value, e.g. "--foo bar".

◆ help_switch

typedef fcppt::options::switch_< fcppt::options::detail::help_label> fcppt::options::help_switch

The type of a help parser.

A help parser is a switch used to display a help message.

◆ help_text

A string type representing a help text.

◆ inactive_value

A strong typedef used as a parser's inactive value.

◆ long_name

A string type representing a long name.

A long name is the name of an argument, e.g. "arg", or the long name of an option or flag, e.g. "--foo".

◆ missing_error

A string type representing a missing error.

A missing error is an error that occurs if a required argument or option has not been specified. Such an error makes fcppt::options::optional parsers return an empty optional.

◆ optional_help_text

An optional help text.

◆ optional_short_name

An optional short name.

◆ other_error

A string type representing other errors.

Errors that are not fcppt::options::missing_error, for example failed conversion. Such errors make even fcppt::options::optional parsers fail.

◆ result

template<typename T >
using fcppt::options::result = typedef fcppt::either::object< fcppt::options::error, T >

The result of a parse.

The result of a parse is either T or an fcppt::options::error.

◆ result_of

template<typename Parser >
using fcppt::options::result_of = typedef typename fcppt::options::detail::result_of< Parser >::type

The result of a parser type.

Template Parameters
ParserEither a parser or an fcppt::options::base_unique_ptr.

◆ short_name

A string type representing a short name.

A short name is the short name of an option or flag, e.g. "-f".

Function Documentation

◆ apply()

template<typename... Parsers>
auto fcppt::options::apply ( Parsers &&...  _parsers)
inline

Combines two or more parsers.

Combines two or more parsers into a single one that parses everything the individual parsers do. Because the resulting parser produces a record that contains all labels of the individual parsers, the label sets of the individual parsers must be pairwise disjoint.

Template Parameters
ParsersMust be at least two parsers.

◆ default_help_switch()

FCPPT_OPTIONS_DETAIL_SYMBOL fcppt::options::help_switch fcppt::options::default_help_switch ( )

The default help switch.

The default help switch that use "-h" or "--help".

◆ is_option()

FCPPT_OPTIONS_DETAIL_SYMBOL bool fcppt::options::is_option ( fcppt::string const &  )

Checks if a string is an option.

Options are strings that with a '-'.

◆ make_active_value()

template<typename Type >
fcppt::options::active_value< typename std::decay< Type >::type> fcppt::options::make_active_value ( Type &&  _value)
inline

Creates an active value.

◆ make_base()

template<typename Result , typename Parser >
fcppt::options::base_unique_ptr< Result> fcppt::options::make_base ( Parser &&  _parser)

Creates an fcppt::options::base.

Creates a unique pointer to fcppt::options::base, using the concrete parser _parser as its implementation. It is possible that the result type of Parser is a permuted version of Result.

Template Parameters
ResultThe result type of the parser. Must be an fcppt::record::object.

◆ make_default_value()

template<typename Type >
fcppt::options::default_value< typename std::decay< Type >::type> fcppt::options::make_default_value ( Type &&  _value)
inline

Creates a default value.

Template Parameters
TypeMust be an fcppt::optional::object.

◆ make_inactive_value()

template<typename Type >
fcppt::options::inactive_value< typename std::decay< Type >::type> fcppt::options::make_inactive_value ( Type &&  _value)
inline

Creates an inactive value.

◆ make_many()

template<typename Parser >
fcppt::options::many< typename std::decay< Parser >::type> fcppt::options::make_many ( Parser &&  _parser)
inline

Turns a parser into a many parser.

Normally, a parser can be applied exactly once. This function turns a parser into a parser that can be applied zero or more times.

◆ make_optional()

template<typename Parser >
fcppt::options::optional< typename std::decay< Parser >::type> fcppt::options::make_optional ( Parser &&  _parser)
inline

Turns a parser into an optional parser.

Normally, a parser can fail, for example in case an argument has not been specified. This function turns a parser into a parser that instead of failing returns optional results.

◆ no_default_value()

template<typename Type >
fcppt::options::default_value< fcppt::optional::object< Type >> fcppt::options::no_default_value ( )
inline

Creates an empty default value.

◆ parse()

template<typename Parser >
fcppt::options::result< fcppt::options::result_of< Parser >> fcppt::options::parse ( Parser const &  _parser,
fcppt::args_vector const &  _args 
)

Parse a command-line.

Applies _parser to _args.

◆ parse_help()

template<typename Parser >
fcppt::options::help_result< fcppt::options::result_of< Parser >> fcppt::options::parse_help ( fcppt::options::help_switch const &  _help,
Parser const &  _parser,
fcppt::args_vector const &  _args 
)

Parse a command-line with a help parser.

First, the switch parser _help is applied to _args. If its switch and nothing else is specified, the usage string is gathered from _parser and returned. Otherwise, if the switch of _help was not specified, then the result of applying _parser to _args is returned.

Warning
Do not include any short or long names in _parser that _help is using.

◆ pretty_type()

template<typename Type >
fcppt::string fcppt::options::pretty_type ( )
inline

Returns a pretty type used for help texts.

Using fcppt::options::pretty_type_impl, one can specialize how a type name is represented as a string. For example, the pretty name of std::string is simply string instead of std::basic_string<char,std::char_traits<char>,std::allocator<char>>.