Argument Parser for Modern C++

argparse

travis license version

Highlights

  • Single header file
  • Requires C++17
  • MIT License

Quick Start

Simply include argparse.hpp and you're good to go.

#include <argparse/argparse.hpp>

To start parsing command-line arguments, create an ArgumentParser.

argparse::ArgumentParser program("program name");

NOTE: There is an optional second argument to the ArgumentParser which is the program version. Example: argparse::ArgumentParser program("libfoo", "1.9.0");

To add a new argument, simply call .add_argument(...). You can provide a variadic list of argument names that you want to group together, e.g., -v and --verbose

program.add_argument("foo");
program.add_argument("-v", "--verbose"); // parameter packing

Argparse supports a variety of argument types including positional, optional, and compound arguments. Below you can see how to configure each of these types:

Positional Arguments

Here's an example of a positional argument:

#include <argparse/argparse.hpp>

int main(int argc, char *argv[]) {
  argparse::ArgumentParser program("program name");

  program.add_argument("square")
    .help("display the square of a given integer")
    .scan<'i', int>();

  try {
    program.parse_args(argc, argv);
  }
  catch (const std::runtime_error& err) {
    std::cout << err.what() << std::endl;
    std::cout << program;
    exit(0);
  }

  auto input = program.get<int>("square");
  std::cout << (input * input) << std::endl;

  return 0;
}

And running the code:

$ ./main 15
225

Here's what's happening:

  • The add_argument() method is used to specify which command-line options the program is willing to accept. In this case, I’ve named it square so that it’s in line with its function.
  • Command-line arguments are strings. To square the argument and print the result, we need to convert this argument to a number. In order to do this, we use the .scan method to convert user input into an integer.
  • We can get the value stored by the parser for a given argument using parser.get<T>(key) method.

Optional Arguments

Now, let's look at optional arguments. Optional arguments start with - or --, e.g., --verbose or -a. Optional arguments can be placed anywhere in the input sequence.

argparse::ArgumentParser program("test");

program.add_argument("--verbose")
  .help("increase output verbosity")
  .default_value(false)
  .implicit_value(true);

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

if (program["--verbose"] == true) {
    std::cout << "Verbosity enabled" << std::endl;
}
$ ./main --verbose
Verbosity enabled

Here's what's happening:

  • The program is written so as to display something when --verbose is specified and display nothing when not.
  • Since the argument is actually optional, no error is thrown when running the program without --verbose. Note that by using .default_value(false), if the optional argument isn’t used, it's value is automatically set to false.
  • By using .implicit_value(true), the user specifies that this option is more of a flag than something that requires a value. When the user provides the --verbose option, it's value is set to true.

Requiring optional arguments

There are scenarios where you would like to make an optional argument required. As discussed above, optional arguments either begin with - or --. You can make these types of arguments required like so:

program.add_argument("-o", "--output")
  .required()
  .help("specify the output file.");

If the user does not provide a value for this parameter, an exception is thrown.

Alternatively, you could provide a default value like so:

program.add_argument("-o", "--output")
  .default_value(std::string("-"))
  .required()
  .help("specify the output file.");

Accessing optional arguments without default values

If you require an optional argument to be present but have no good default value for it, you can combine testing and accessing the argument as following:

if (auto fn = program.present("-o")) {
    do_something_with(*fn);
}

Similar to get, the present method also accepts a template argument. But rather than returning T, parser.present<T>(key) returns std::optional<T>, so that when the user does not provide a value to this parameter, the return value compares equal to std::nullopt.

Deciding if the value was given by the user

If you want to know whether the user supplied a value for an argument that has a .default_value, check whether the argument .is_used().

program.add_argument("--color")
  .default_value("orange")
  .help("specify the cat's fur color");

try {
  program.parse_args(argc, argv);    // Example: ./main --color orange
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto color = program.get<std::string>("--color");  // "orange"
auto explicit_color = program.is_used("--color");  // true, user provided orange

Joining values of repeated optional arguments

You may want to allow an optional argument to be repeated and gather all values in one place.

program.add_argument("--color")
  .default_value<std::vector<std::string>>({ "orange" })
  .append()
  .help("specify the cat's fur color");

try {
  program.parse_args(argc, argv);    // Example: ./main --color red --color green --color blue
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto colors = program.get<std::vector<std::string>>("--color");  // {"red", "green", "blue"}

Notice that .default_value is given an explicit template parameter to match the type you want to .get.

Negative Numbers

Optional arguments start with -. Can argparse handle negative numbers? The answer is yes!

argparse::ArgumentParser program;

program.add_argument("integer")
  .help("Input number")
  .scan<'i', int>();

program.add_argument("floats")
  .help("Vector of floats")
  .nargs(4)
  .scan<'g', float>();

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

// Some code to print arguments
$ ./main -5 -1.1 -3.1415 -3.1e2 -4.51329E3
integer : -5
floats  : -1.1 -3.1415 -310 -4513.29

As you can see here, argparse supports negative integers, negative floats and scientific notation.

Combining Positional and Optional Arguments

argparse::ArgumentParser program("test");

program.add_argument("square")
  .help("display the square of a given number")
  .scan<'i', int>();

program.add_argument("--verbose")
  .default_value(false)
  .implicit_value(true);

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

int input = program.get<int>("square");

if (program["--verbose"] == true) {
  std::cout << "The square of " << input << " is " << (input * input) << std::endl;
}
else {
  std::cout << (input * input) << std::endl;
}
$ ./main 4
16

$ ./main 4 --verbose
The square of 4 is 16

$ ./main --verbose 4
The square of 4 is 16

Printing Help

std::cout << program prints a help message, including the program usage and information about the arguments registered with the ArgumentParser. For the previous example, here's the default help message:

$ ./main --help
Usage: ./main [options] square

Positional arguments:
square         display a square of a given number

Optional arguments:
-h, --help     show this help message and exit
-v, --verbose  enable verbose logging

You may also get the help message in string via program.help().str().

List of Arguments

ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The .nargs associates a different number of command-line arguments with a single action. When using nargs(N), N arguments from the command line will be gathered together into a list.

argparse::ArgumentParser program("main");

program.add_argument("--input_files")
  .help("The list of input files")
  .nargs(2);

try {
  program.parse_args(argc, argv);   // Example: ./main --input_files config.yml System.xml
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto files = program.get<std::vector<std::string>>("--input_files");  // {"config.yml", "System.xml"}

ArgumentParser.get<T>() has specializations for std::vector and std::list. So, the following variant, .get<std::list>, will also work.

auto files = program.get<std::list<std::string>>("--input_files");  // {"config.yml", "System.xml"}

Using .scan, one can quickly build a list of desired value types from command line arguments. Here's an example:

argparse::ArgumentParser program("main");

program.add_argument("--query_point")
  .help("3D query point")
  .nargs(3)
  .default_value(std::vector<double>{0.0, 0.0, 0.0})
  .scan<'g', double>();

try {
  program.parse_args(argc, argv); // Example: ./main --query_point 3.5 4.7 9.2
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto query_point = program.get<std::vector<double>>("--query_point");  // {3.5, 4.7, 9.2}

Compound Arguments

Compound arguments are optional arguments that are combined and provided as a single argument. Example: ps -aux

argparse::ArgumentParser program("test");

program.add_argument("-a")
  .default_value(false)
  .implicit_value(true);

program.add_argument("-b")
  .default_value(false)
  .implicit_value(true);

program.add_argument("-c")
  .nargs(2)
  .default_value(std::vector<float>{0.0f, 0.0f})
  .scan<'g', float>();

try {
  program.parse_args(argc, argv);                  // Example: ./main -abc 1.95 2.47
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto a = program.get<bool>("-a");                  // true
auto b = program.get<bool>("-b");                  // true
auto c = program.get<std::vector<float>>("-c");    // {1.95, 2.47}

/// Some code that prints parsed arguments
$ ./main -ac 3.14 2.718
a = true
b = false
c = {3.14, 2.718}

$ ./main -cb
a = false
b = true
c = {0.0, 0.0}

Here's what's happening:

  • We have three optional arguments -a, -b and -c.
  • -a and -b are toggle arguments.
  • -c requires 2 floating point numbers from the command-line.
  • argparse can handle compound arguments, e.g., -abc or -bac or -cab. This only works with short single-character argument names.
    • -a and -b become true.
    • argv is further parsed to identify the inputs mapped to -c.
    • If argparse cannot find any arguments to map to c, then c defaults to {0.0, 0.0} as defined by .default_value

Converting to Numeric Types

For inputs, users can express a primitive type for the value.

The .scan<Shape, T> method attempts to convert the incoming std::string to T following the Shape conversion specifier. An std::invalid_argument or std::range_error exception is thrown for errors.

program.add_argument("-x")
       .scan<'d', int>();

program.add_argument("scale")
       .scan<'g', double>();

Shape specifies what the input "looks like", and the type template argument specifies the return value of the predefined action. Acceptable types are floating point (i.e float, double, long double) and integral (i.e. signed char, short, int, long, long long).

The grammar follows std::from_chars, but does not exactly duplicate it. For example, hexadecimal numbers may begin with 0x or 0X and numbers with a leading zero may be handled as octal values.

Shape interpretation
'a' or 'A' hexadecimal floating point
'e' or 'E' scientific notation (floating point)
'f' or 'F' fixed notation (floating point)
'g' or 'G' general form (either fixed or scientific)
'd' decimal
'i' std::from_chars grammar with base == 0
'o' octal (unsigned)
'u' decimal (unsigned)
'x' or 'X' hexadecimal (unsigned)

Gathering Remaining Arguments

argparse supports gathering "remaining" arguments at the end of the command, e.g., for use in a compiler:

$ compiler file1 file2 file3

To enable this, simply create an argument and mark it as remaining. All remaining arguments passed to argparse are gathered here.

argparse::ArgumentParser program("compiler");

program.add_argument("files")
  .remaining();

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

try {
  auto files = program.get<std::vector<std::string>>("files");
  std::cout << files.size() << " files provided" << std::endl;
  for (auto& file : files)
    std::cout << file << std::endl;
} catch (std::logic_error& e) {
  std::cout << "No files provided" << std::endl;
}

When no arguments are provided:

$ ./compiler
No files provided

and when multiple arguments are provided:

$ ./compiler foo.txt bar.txt baz.txt
3 files provided
foo.txt
bar.txt
baz.txt

The process of gathering remaining arguments plays nicely with optional arguments too:

argparse::ArgumentParser program("compiler");

program.add_arguments("-o")
  .default_value(std::string("a.out"));

program.add_argument("files")
  .remaining();

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto output_filename = program.get<std::string>("-o");
std::cout << "Output filename: " << output_filename << std::endl;

try {
  auto files = program.get<std::vector<std::string>>("files");
  std::cout << files.size() << " files provided" << std::endl;
  for (auto& file : files)
    std::cout << file << std::endl;
} catch (std::logic_error& e) {
  std::cout << "No files provided" << std::endl;
}
$ ./compiler -o main foo.cpp bar.cpp baz.cpp
Output filename: main
3 files provided
foo.cpp
bar.cpp
baz.cpp

NOTE: Remember to place all optional arguments BEFORE the remaining argument. If the optional argument is placed after the remaining arguments, it too will be deemed remaining:

$ ./compiler foo.cpp bar.cpp baz.cpp -o main
5 arguments provided
foo.cpp
bar.cpp
baz.cpp
-o
main

Parent Parsers

Sometimes, several parsers share a common set of arguments. Rather than repeating the definitions of these arguments, a single parser with all the common arguments can be added as a parent to another ArgumentParser instance. The .add_parents method takes a list of ArgumentParser objects, collects all the positional and optional actions from them, and adds these actions to the ArgumentParser object being constructed:

argparse::ArgumentParser parent_parser("main");
parent_parser.add_argument("--parent")
  .default_value(0)
  .scan<'i', int>();

argparse::ArgumentParser foo_parser("foo");
foo_parser.add_argument("foo");
foo_parser.add_parents(parent_parser);
foo_parser.parse_args({ "./main", "--parent", "2", "XXX" });   // parent = 2, foo = XXX

argparse::ArgumentParser bar_parser("bar");
bar_parser.add_argument("--bar");
bar_parser.parse_args({ "./main", "--bar", "YYY" });           // bar = YYY

Note You must fully initialize the parsers before passing them via .add_parents. If you change the parent parsers after the child parser, those changes will not be reflected in the child.

Further Examples

Construct a JSON object from a filename argument

argparse::ArgumentParser program("json_test");

program.add_argument("config")
  .action([](const std::string& value) {
    // read a JSON file
    std::ifstream stream(value);
    nlohmann::json config_json;
    stream >> config_json;
    return config_json;
  });

try {
  program.parse_args({"./test", "config.json"});
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

nlohmann::json config = program.get<nlohmann::json>("config");

Positional Arguments with Compound Toggle Arguments

argparse::ArgumentParser program("test");

program.add_argument("numbers")
  .nargs(3)
  .scan<'i', int>();

program.add_argument("-a")
  .default_value(false)
  .implicit_value(true);

program.add_argument("-b")
  .default_value(false)
  .implicit_value(true);

program.add_argument("-c")
  .nargs(2)
  .scan<'g', float>();

program.add_argument("--files")
  .nargs(3);

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto numbers = program.get<std::vector<int>>("numbers");        // {1, 2, 3}
auto a = program.get<bool>("-a");                               // true
auto b = program.get<bool>("-b");                               // true
auto c = program.get<std::vector<float>>("-c");                 // {3.14f, 2.718f}
auto files = program.get<std::vector<std::string>>("--files");  // {"a.txt", "b.txt", "c.txt"}

/// Some code that prints parsed arguments
$ ./main 1 2 3 -abc 3.14 2.718 --files a.txt b.txt c.txt
numbers = {1, 2, 3}
a = true
b = true
c = {3.14, 2.718}
files = {"a.txt", "b.txt", "c.txt"}

Restricting the set of values for an argument

argparse::ArgumentParser program("test");

program.add_argument("input")
  .default_value("baz")
  .action([](const std::string& value) {
    static const std::vector<std::string> choices = { "foo", "bar", "baz" };
    if (std::find(choices.begin(), choices.end(), value) != choices.end()) {
      return value;
    }
    return std::string{ "baz" };
  });

try {
  program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
  std::cout << err.what() << std::endl;
  std::cout << program;
  exit(0);
}

auto input = program.get("input");
std::cout << input << std::endl;
$ ./main fex
baz

Supported Toolchains

Compiler Standard Library Test Environment
GCC >= 8.3.0 libstdc++ Ubuntu 18.04
Clang >= 7.0.0 libc++ Xcode 10.2
MSVC >= 14.16 Microsoft STL Visual Studio 2017

Contributing

Contributions are welcome, have a look at the CONTRIBUTING.md document for more information.

Contributors

Thanks goes to these wonderful people:

svanveen
svanveen
Zhihao Yuan
Zhihao Yuan
Mio
Mio
zhihaoy
zhihaoy
Jack Clarke
Jack Clarke
Daniel Marshall
Daniel Marshall
mupp
mupp
Ethan Slattery
Ethan Slattery

License

The project is available under the MIT license.

Comments
  • Fixed issue #119 and a few other minor code improvements.

    Fixed issue #119 and a few other minor code improvements.

    This PR fixes the issue #119 , and also makes a few minor code readability and performance improvements discussed as follows:

    1. The argparse::ArgumentParser::parse_args_validate() method uses a for each loop instead of std::for_each as it is more readable and performs the same task.

    2. The argparse::ArgumentParser::get_length_of_longest_argument() method now does not make use of an std::vector and runs in a better O(1) space complexity.

    3. The issue of printing overriden args (which btw is the issue #119 ), has been fixed and it now prints the overriden/ updated values.

    Before: image

    After: image

  • conan package 2.1 does not match 2.1 tag

    conan package 2.1 does not match 2.1 tag

    related to my comment here: https://github.com/p-ranav/argparse/issues/2 conan package https://conan.io/center/argparse does not match: https://github.com/p-ranav/argparse/tree/v2.1 for example, it does not have "scan" function. anything that I am missing? I basically cannot do something very simple as:

        program.add_argument("--something")
            .default_value(0);
    

    if I pass --something 10 in the cmd line arg, I'm getting bad cast when trying to interpret it as int:

    program.get<int>("--something");
    

    It is as if I need to have all std::any be strings and then manually convert it to ints. I need something like boost which has the .as<T>()

    Any pointers are appreciated. thanks

  • Improve nargs

    Improve nargs

    Hi. Thank you for this nice library.

    I see some issues regarding "remaining" behavior.

    https://github.com/p-ranav/argparse/issues/118 https://github.com/p-ranav/argparse/issues/81

    I also wanted optional argument preceded by variable length positional arguments (including zero length) like Python argparse nargs "*", "+", "?"

    So, I implemented it just for experiment. For now, this worked for me.

    I know this change drops "remaining" feature, which would impact existing projects. Also, this seems a complicated problem and I think more study may be needed.

    What do you think about this change?

    Thank you in advance.

  • Change coding style for argparse

    Change coding style for argparse

    • Change private member variable names to be (1) underscore separated, (2) all lower case, (3) with a trailing underscore, e.g., my_private_variable_ instead of mMyPrivateVariable.
    • Change member function names to be (1) underscore separated, (2) all lower case, (3) with a trailing underscore if the member function is private, e.g., my_public_member_function(), and my_private_member_function_()
    • Change function parameter names to be (1) underscore separated, (2) all lower case, e.g., my_function(int foo, float bar)
    • Class names will be PascalCase, e.g., ArgumentParser
    • Add clang-format configuration and use the standard LLVM coding style

    From:

      std::vector<std::string> mNames;
      std::string_view mUsedName;
    

    To:

      std::vector<std::string> names_;
      std::string_view used_name_;
    
  • Refactoring `present` and `get`

    Refactoring `present` and `get`

    This PR does a few things:

    • Formats the code.
    • Replaces pointer any_casts with reference any_casts.
    • Removes the use of optional from present
    • Separates get into container and non-container counterparts.
    • Separates present into container and non-container counterparts.
    • For containers, present always returns at least an empty container.
  • Add ability to check if `ArgumentParser` parsed any input

    Add ability to check if `ArgumentParser` parsed any input

    EDIT: see the discussion below for more information on how this issue evolved

    First I want to say thank you so much for the excellent work done on this library! I was hoping I could request a feature regarding subcommands.

    I am building out a utility that requires the user to primarily use a subcommand to trigger any useful behavior. Essentially the desired behavior is:

    • Setup parser with subcommands
    • Parse arguments
    • Check if any subcommand has been used
      • If yes, do subcommand stuff
      • If no, print help message and exit with error code

    This would be similar behavior as running git with no subcommands.

    I was looking through the header, and it appears the way to do this is use the member function ArgumentParser::is_subcommand_used. To achieve the above described effect, I would need to loop over a list of hard-coded commands from a separate list. This isn't the end of the world of course, since it's pretty simple to keep a list of the commands that have been implemented.

    However, it would be nice to be able to do something like:

    // setup "program" with subcommands and parse_args
    // ...
    
    if (!program.has_used_subcommands())
    {
        std::cerr << program;
        std::exit(1);
    }
    

    A potential implementation could just be a wrapper function around m_subparser_used (not sure how correct this is, not tested):

    auto has_used_subcommands()
    {
        return std::any_of(m_subparser_used.begin(), m_subparser_used.end(),
            [](const auto& it){ return it.second; });
    }
    

    Although, this does present an ancillary consideration of checking which subcommand was used. So perhaps it would be better to return a std::optional reference from m_subparsers to the subcommand, and just return std::nullopt if none were used (which would allow the same conditional check described above).

    Edit: fixed a typo Edit 2: fixed error with lamda

  • argparse.hpp doesn't compile : 2 errors thrown

    argparse.hpp doesn't compile : 2 errors thrown

    Hello, I might have done something wrong so i ask you what i could have done wrong. I first copy your argparse.hpp file in my project, and called it. When I try to compile the project, two errors are thrown :

    • no matching function for call to ‘argparse::Argument::get<char [1]>() const’ (gcc [Ln 586, Col23])
    • function returning an array (gcc, [Ln 777,Col27] Did I miss something ? Thank you for your help. Have a nice day. (Sorry for my english)
  • ArgumentParser as a container

    ArgumentParser as a container

    Recent Issues (#217, #224) make me think people want container-like access to ArgumentParser. I'm considering adding ArgumentParser::at to return Argument and subparser instances.

    template <typename T = Argument>
    T ArgumentParser::at(const std::string key) {}
    
    auto help_arg = program.at("--help");
    auto add_cmd = program.at<ArgumentParser>("add");
    

    Thoughts, @p-ranav, @lingerer, @bwpge?

  • Printing program version

    Printing program version

    Python's argparse has a special action that prints the program version and exits.

    Currently printing the program version with this library can be done, but the presence of required arguments will also cause an error.

    Support for printing the program version would be nice to have as it's an expected part of any CLI, akin to the --help option.

  • What if actions want to return std::vector?

    What if actions want to return std::vector?

    If an option wants to parse a list of values --foo 1,4,2,6, then it cannot return std::vector<int> because this type is considered a container. We probably will never want to parse a list like that (because there are so many good parsing libraries for structural data), so we cannot return the existing containers functionality to "make get<std::vector<T>>() work" for this demand.

    We should consider changing the multivalue argument support. Some observations:

    • Blessing types takes away possible return types
    • std::vector<std::string> is verbose to spell
    • std::array is not supported (and is tricky to support, because it's not a container that can grow)
    • std::list is probably never used for lots of reasons

    Inventing a new set of API is an option, but the present API (#66) will double the number of names. I think the situation can be improved by blessing a type that is both impossible to be stored in std::any, and is terse to write -- array type.

    Here is how the new get may look like:

    • get<T[]>: returns std::vector<T>
    • get<T[N]>: returns std::array<T, N> if N == nargs, throws otherwise
    • get<T>: returns T

    The old spelling get<std::vector<std::string>> becomes get<std::string[]> after the change. To not to break everything immediately, we can make the old spelling [[deprecated]].

    FAQ

    1. Why T[] and T[N] return entirely different types? I hope users can interpret [] as "returning a type with operator[]."
    2. Why not other kinds of containers? If users want they can append to anything with void actions. We are providing a good default here.
    3. Why not std::span (of static extent or dynamic extent)? Technical issue, we only have storage for std::vector<std::any> rather than std::vector<T>.
  • Use references for any_cast

    Use references for any_cast

    This PR optimizes 'get' by returning references as opposed to values. This decreases the theoretical memory usage by 50% since values are no longer passed by value. This also let's the compiler free to optimize these calls since L-values are not returned for non-containers.

  • Proposed update to remove RAII problem

    Proposed update to remove RAII problem

    I propose the removal of the use of std::exit. It's usage breaks RAII which is not mentioned in the documentation.

    As for the addition of the exception, during parsing we already require that the user catches several exceptions thus the whole try/catch harness is already there for a proper program. Adding a catch clause for the new NormalProgramTermination is a bit bulky but doesn't break RAII and is explicit on that the program should terminate in normal usage.

  • Segmentation fault when parsing double

    Segmentation fault when parsing double

     argparse::ArgumentParser args("Demo");
     args.add_argument("--gain").help("Gain").required().default_value(40.0);
    
    try {
            args.parse_args(argc, argv);
        }
        catch (const std::runtime_error& err) {
            std::cerr << err.what() << std::endl;
            std::cerr << args;
            std::exit(1);
        }
    
    auto val = args.get<double>("--gain");
        printf("%f\n", val);
    

    By default, it runs fine and prints 40.000. If i run with --gain 30.0, I get a segmentation fault

  • Segmentation fault when default value is C-style string

    Segmentation fault when default value is C-style string

    argparse::ArgumentParser args("Demo");
    args.add_argument("--arg").help("Some string arg").required().default_value("bug alert");
    

    Fix:

    argparse::ArgumentParser args("Demo");
    args.add_argument("--arg").help("Some string arg").required().default_value(std::string("ok"));
    

    Maybe default_value() should have an overload for const char* which automatically converts to std::string

  • Correct vertical alignment for multi-line help message

    Correct vertical alignment for multi-line help message

    Issue

    Currently, a multi-line help message would look something like:

    Positional arguments:
      program_inputs        This is the first line of help text.
    And this is the second line of help text. (MISALIGNED)
    
    Optional arguments:
      -h, --help            shows help message and exits 
      -v, --version         prints version information and exits 
    

    This is produced from the C++ code:

    argparse::ArgumentParser program("program");
    program.add_argument("program_inputs")
        .help(
            "This is the first line of help text.\n"
            "And this is the second line of help text."
        );
    

    Expecting

    Is it possible to make the multi-line help message aligns properly?

    Positional arguments:
      program_inputs        This is the first line of help text.
                            And this is the second line of help text. (ALIGNED)
    
    Optional arguments:
      -h, --help            shows help message and exits 
      -v, --version         prints version information and exits 
    

    If not, is there a way, as a hack, to access the number of spaces needed to add prior to the second line of the help message?

    Thank you.

  • 'Too few arguments' not works at the end of the parameters ?

    'Too few arguments' not works at the end of the parameters ?

    here is my key code:

        parser.add_argument("-inc_chr", "--include_chromes")
                    .help(string("only process the anchor whose one of the end is contained on the specified "
                                 "chromatin, used ',' to split."))
                    .default_value("all");
    
        try {
            program.parse_args(argc, argv);
        } catch (const std::runtime_error& err) {
            std::cerr << err.what() << std::endl;
            std::cerr << program;
            std::exit(1);
        } catch (const std::logic_error& err) {
            std::cerr << err.what() << std::endl;
            std::cerr << program;
            std::exit(1);
        };
    

    cmd 1 success worked:

    D:\code\C++\InterLoop\cmake-build-debug\InterLoop.exe  -inc_chr -lo my.log
    Too few arguments
    Usage: InterLoop [--help] [--version] [--include_chromes VAR]  [--log_output VAR]
    
    

    cmd 2 not worked:

    D:\code\C++\InterLoop\cmake-build-debug\InterLoop.exe  -lo my.log -inc_chr
    
    Process finished with exit code -1073741819 (0xC0000005)
    

    And I found it not works only at the end of command line.

    Can anyone help me to make cmd 2 consistent with cmd 1, thanks a lot !

A simple header-only C++ argument parser library. Supposed to be flexible and powerful, and attempts to be compatible with the functionality of the Python standard argparse library (though not necessarily the API).

args Note that this library is essentially in maintenance mode. I haven't had the time to work on it or give it the love that it deserves. I'm not add

Aug 31, 2021
⛳ Simple, extensible, header-only C++17 argument parser released into the public domain.

⛳ flags Simple, extensible, header-only C++17 argument parser released into the public domain. why requirements api get get (with default value) posit

Dec 11, 2022
easy to use, powerful & expressive command line argument parsing for modern C++ / single header / usage & doc generation

clipp - command line interfaces for modern C++ Easy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a sing

Dec 29, 2022
Argh! A minimalist argument handler.

Frustration-free command line processing So many different command line processing libraries out there and none of them just work! Some bring their wh

Dec 28, 2022
udmp-parser: A Windows user minidump C++ parser library.
udmp-parser: A Windows user minidump C++ parser library.

udmp-parser: A Windows user minidump C++ parser library. This is a cross-platform (Windows / Linux / OSX / x86 / x64) C++ library that parses Windows

Dec 13, 2022
A simple to use, composable, command line parser for C++ 11 and beyond

Clara v1.1.5 !! This repository is unmaintained. Go here for a fork that is somewhat maintained. !! A simple to use, composable, command line parser f

Dec 27, 2022
CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.
CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.

CLI11: Command line parser for C++11 What's new • Documentation • API Reference CLI11 is a command line parser for C++11 and beyond that provides a ri

Dec 30, 2022
Lightweight C++ command line option parser

Release versions Note that master is generally a work in progress, and you probably want to use a tagged release version. Version 3 breaking changes I

Dec 30, 2022
A simple to use, composable, command line parser for C++ 11 and beyond

Lyra A simple to use, composing, header only, command line arguments parser for C++ 11 and beyond. Obtain License Standards Stats Tests License Distri

Dec 22, 2022
Tiny command-line parser for C / C++

tinyargs Another commandline argument parser for C / C++. This one is tiny, source only, and builds cleanly with -Wall -pedantic under C99 and C++11 o

Aug 22, 2022
Elf and PE file parser

PelfParser PelfParser is a very simple C++ library for parsing Windows portable executable files and Executable and Linkable Format files, it only sup

Oct 29, 2021
A math parser made in 1 hour using copilot.

An entire math parser made with Copilot Copilot wrote 91% of the code in this, amazing isn't it? It supports all normal mathematical expressions excep

Dec 7, 2021
A parser for InnoDB file formats

Introduction Inno_space is a parser for InnoDB file formats. It parse the .ibd file to human readable format. The origin idea come from Jeremy Cole's

Dec 19, 2022
An extremely fast FEC filing parser written in C

FastFEC A C program to stream and parse FEC filings, writing output to CSV. This project is in early stages but works on a wide variety of filings and

Nov 3, 2022
JSONes - c++ json parser & writer. Simple api. Easy to use.

JSONes Just another small json parser and writer. It has no reflection or fancy specs. It is tested with examples at json.org Only standart library. N

Dec 28, 2021
A simple parser for the PBRT file format
A simple parser for the PBRT file format

PBRT-Parser (V1.1) The goal of this project is to provide a free (apache-lincensed) open source tool to easily (and quickly) load PBRT files (such as

Jan 1, 2023
A library for interactive command line interfaces in modern C++
A library for interactive command line interfaces in modern C++

cli A cross-platform header only C++14 library for interactive command line interfaces (Cisco style) Features Header only Cross-platform (linux and wi

Dec 31, 2022
Activity Indicators for Modern C++
Activity Indicators for Modern C++

Highlights Thread-safe progress bars and spinners Header-only library. Grab a copy of include/indicators. Single-header version in single_include/indi

Jan 4, 2023
Table Maker for Modern C++
Table Maker for Modern C++

Source for the above image can be found here Table of Contents Quick Start Formatting Options Style Inheritance Model Word Wrapping Font Alignment Fon

Dec 30, 2022