Skip to content

jpan127/argparse

Repository files navigation

Description

A C++14 compliant command line parser.

Implemented Features

  • Strongly typed command line options
  • Letter-based or string-based options
  • Enforcing requirement of specific options
  • Allowed values for a specific option
  • Default values for a specific option
  • Subparsing, various parsers that depend on the value of a preceding option

Build Status

Branch Build Status
master Build Status
feature Build Status

Supported Compilers

OS Compiler
Linux Clang 8.X
Linux Clang 7.X
Linux Clang 6.X
Linux GCC 8.X
Linux GCC 7.X
Linux GCC 6.X
Linux GCC 5.X

Usage

1. Create a Parser object

#include "argparse/argparse.h"
argparse::Parser p("my name", "my cool program");

2. Add options

Add a non positional option.

  • Starting value is "yaml" if no values are provided
  • Provided value must be either cpp, yaml, or py
  • The option can be specified with --type <value> or -t <value>
  • The help text is displayed in a table when -h, --help is provided or on error
  • The required flag tells the parser to enforce any options to be present
const auto type = p.add(argparse::Config<std::string>{
    .default_value = "yaml",
    .allowed_values = {"cpp", "yaml", "py"},
    .name = "type",
    .help = "Type of the input file",
    .required = true,
    .letter = 't',
});

Add a positional option.

  • The configuration applies the same as a non positional
  • The positional arguments are expected in the order they are added
const auto first  = p.add_leading_positional(argparse::Config<std::string>{ .name = "first"  });
const auto second = p.add_leading_positional(argparse::Config<std::string>{ .name = "second" });
const auto third  = p.add_leading_positional(argparse::Config<std::string>{ .name = "third"  });

// Expected call
<PROGRAM_NAME> <first VALUE> <second VALUE> <third VALUE>

Add a multivalent option.

  • The configuration applies the same as a non positional
  • This option can have multiple values
  • It will parse all the values after the --name or -letter flag until the next flag
const auto values = p.add_multivalent(argparse::Config<std::string>{ .name = "values" });

// Expected call
<PROGRAM_NAME> --values value1 value2 value3

3. Parse the arguments

  • After all options are registered, the command line arguments need to be parsed
  • Any additional arguments provided after -- will be stored in a vector returned by parse
const auto &remaining_arguments = p.parse(argc, argv);

4. Use the parsed arguments

  • Every add function returns a ConstPlaceHolder<T>
  • Every add_multivalent function returns a ConstPlaceHolder<std::vector<T>>
  • This placeholder is a std::shared_ptr<optional<T>>
  • The std::shared_ptr wrapper is so that the value can be populated at parsing
  • The optional second wrapper is to signify whether there exists a value
  • This library uses tl::optional as the optional implementation since C++14 does not support it yet tl::optional
// Example option
const auto option = p.add(argparse::Config<std::string>{ ... });

// We can assume the pointer is valid
assert(option);

// First we can check if the value exists
if (option->has_value()) {
    ...
}

// Next we can get a const reference to the value
const auto &value = option->value();

// Or use it directly
if (option->value() == "some expected value") {
    ...
}

What happens on failure?

  • On any failure, errors are printed in red of the cause
  • The usage, description, and information about the options are printed
  • Then the program will throw a std::runtime_error exception

This is the help text from the sample program:

Usage: Sample Program [mode] [path] [--verbose] [--h] [--id] [--help]
Description: Testing...

Options:
--------------------------------------------------------------------------------------------------------------
|Required|Positional| Name  |Letter|  Type  |Default|             Help             |     Allowed Values      |
--------------------------------------------------------------------------------------------------------------
|        |          |  id   |      |int64_t |       |  some identification number  | 1234 , 9999 , 127127127 |
|        |          |verbose|      |uint64_t|   5   |                              |                         |
|   x    |    2     | path  |      |  bool  |   0   |                              |                         |
|   x    |    1     | mode  |      | string |       |Operation mode of this program|        a , c , b        |
|        |          | help  |  h   |  bool  |   0   |      Show help message       |                         |
--------------------------------------------------------------------------------------------------------------

Subparsers

  • Suppose we wanted a specific argument to determine what options to parse
  • For example we want different options for 3 different modes
  • We can create this by using a subparser, then adding the different options to the subparsers and not the parent parser
  • The value that the subparser will switch on is treated like a leading positional argument
  • It must be specified first, prior to other options
// Create subparsers
auto &subparsers = p.add_subparser("mode", {"read", "write", "append"});

// Split the subparsers into individual parsers
auto &read   = subparsers["read"];
auto &write  = subparsers["write"];
auto &append = subparsers["append"];

// Add options for each subparser
const auto read_only_option = read.add(argparse::Config<std::string>{ .name = "read_only_option" });
const auto write_only_option = write.add(argparse::Config<std::string>{ .name = "write_only_option" });
const auto append_only_option = append.add(argparse::Config<std::string>{ .name = "append_only_option" });

// Expected call
<PROGRAM_NAME> <MODE> <MODE OPTIONS>
./sample read --read_only_option option_value
./sample write --write_only_option option_value
./sample append --append_only_option option_value

Syntax

The add functions take a structure Config<T>. To simplify / prettify the syntax, designated initializers are used in the examples when calling these functions to save a line from declaring the Config<T> variable. With clang the type of the desginated initializers can be deduced and the verbosity of argparse::Config<T> is not necessary. However g++ fails to deduce these contexts, and so all examples and code in this library explicitly specify the object type. If the user is using clang then these can be happily ommitted.

Example clang:

const auto option = p.add<std::string>({ ... });

Supported Types

All of the above examples use std::string as the option type but all fundamental types are supported as well.

More Information

To read more about how the library works, you can start with argparse.h.

About

C++ command line parser

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages