-
Notifications
You must be signed in to change notification settings - Fork 0
Positional Arguments
Defining positional arguments is very similar to options. You need to create and configure a Positional
(or WPositional
) object and add it to a parser via its add()
method. A definition of a positional argument consists of:
-
Name. This is the constructor argument. The name is only visible to user in usage/help strings - otherwise positional arguments are identified by their position (duh!). The name is also used to refer to this positional elsewhere income, such is when using validators.
-
A handler, which is a function object (often a lambda) that is invoked when the position argument is encountered during parsing. A handler is not strictly required - if you don't provide one a default handler simply does nothing. Since doing nothing for a positional is exceedingly rare, usually you do need to provide one. Unlike those for options, handlers for positionals always have one form: they accept an
std::string_view
(orstd::wstring_view
) argument containing the value of the positional. -
A help string. This is the description of the option produced when generating help via
formatHelp
method. Not required but obviously highly desired if you use Argum's generated help. -
Allowed number of occurrences. By default it is "once". You can change that to anything you want including "zero or more", "from 2 to 5" etc.
Putting it all together here is an example of a positional argument that must occur exactly once.
std::string filename;
parser.add(
Positional("filename").
help("name of the file to process").
handler([&](const std::string_view & value) {
filename = value;
}));
Note that the configuration methods can be conveniently chained together. Assuming nothing else, other than help option is defining running this program will produce:
$ ./prog --help
Usage: ./prog [--help] filename
positional arguments:
filename name of the file to process
options:
--help, -h show this help message and exit
The occurs()
method takes a Quantifier
object that specifies minimum and maximum number of times a positional can occur. There are some predefined quantifiers such as: zeroOrOneTime
or neverOrOnce
(both mean the same), oneTime
or once
(this is the default for positionals), zeroOrMoreTimes
and oneOrMoreTimes
or onceOrMore
which cover most common scenarios. For anything else you can pass a
Quantifer(min, max)
. To specify "unlimited" for max pass Quantifer::infinity
.
What happens if you have multiple positionals defined with different quantifiers? How does the parser decide which argument belongs where? The algorithm it follows is very simple:
- First it makes sure that there is enough arguments to satisfy the minima of all of them. If not an error is reported.
- Once the minima are satisfied the parser greedily tries to match up to each positional maximum from left to right. If you are familiar with regular expressions and quantifiers there this is the exact same approach.
Let's look at a concrete example. Consider a utility that takes zero or more source files and one destination file as input. It would be coded like this
int main(int argc, char * argv[]) {
std::vector<std::string> sources;
std::string destination;
const char * progname = (argc ? argv[0] : "prog");
Parser parser;
parser.add(
Positional("source").
help("source file").
occurs(zeroOrMoreTimes).
handler([&](const std::string_view & value) {
sources.emplace_back(value);
}));
parser.add(
Positional("destination").
help("destination file").
occurs(once). //this could be omitted as it is the default
handler([&](const std::string_view & value) {
destination = value;
}));
parser.add(
Option("--help", "-h").help("show this help message and exit").
handler([&]() {
printUsageAndExit(parser, progname);
}));
try {
parser.parse(argc, argv);
} catch (ParsingException & ex) {
std::cerr << ex.message() << '\n';
std::cerr << parser.formatUsage(progname) << '\n';
return EXIT_FAILURE;
}
//join() is a useful helper found in Argum
std::cout << "sources: " << join(sources.begin(), sources.end(), ", ") << '\n';
std::cout << "destination: " << destination << '\n';
}
Running this produces
$ ./prog --help
Usage: ./prog [--help] [source [source ...]] destination
positional arguments:
source source file
destination destination file
options:
--help, -h show this help message and exit
$ ./prog
invalid arguments: positional argument destination must be present
Usage: ./prog [--help] [source [source ...]] destination
$ ./prog a
sources:
destination: a
$ ./prog a b
sources: a
destination: b
$ ./prog a b c
sources: a, b
destination: c
Reporting errors from handlers
Parsing common data types
Validation
- Home
-
Usage Guide
Basics
Error Handling
Thread Safety
Adding Help
Defining options
Positional arguments
Reporting errors from handlers
Parsing common data types
Validation
Depending on order
Subcommands
Response files
Partial Parsing -
Advanced
Syntax Description
Customizing syntax
Customizing usage and help
Localization