Argument Parser for Modern C++

Overview

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

    opened by aayush749 16
  • 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

    opened by kobi-ca 14
  • 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.

    opened by hokacci 14
  • 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_;
    
    enhancement 
    opened by p-ranav 9
  • 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.
    opened by jun-sheaf 8
  • 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

    opened by bwpge 7
  • 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)
    opened by Chabname 7
  • 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.

    opened by ekmecic 6
  • 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>.
    opened by zhihaoy 6
  • 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.

    opened by jun-sheaf 5
  • Fix generic_strtod for clang-cl

    Fix generic_strtod for clang-cl

    Fixed to use explicit template specialization that call the function instead of being a function pointer. The end result is the exact same.

    Fixes https://github.com/p-ranav/argparse/issues/136

    opened by marstaik 5
  • No rule to make target install

    No rule to make target install

    When trying ot install the package as explained in the README, I have the following error:

    make: *** No rule to make target 'install'.  Stop.
    

    I try to build and install in a conda environment with the following command:

    cmake -DCMAKE_PREFIX_PATH=$CONDA_PREFIX -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX $SRC_DIR -DCMAKE_INSTALL_LIBDIR=lib
    

    The following fails the same way:

    cmake $SRC_DIR
    

    I cannot find a reason that would prevent CPack to generate the install command in the Makefile.

    opened by JohanMabille 0
  • Package availability on conda-forge

    Package availability on conda-forge

    Thanks for this great work! I intend to use argparse as a requirement in some software, and realized that the package wasn't available on conda-forge. Am I wrong? If not, is there a reason why it's not? I could also do the work if there isn't another way of simple linking...

    opened by Hind-M 2
  • Dashes in double quoted arg detected as invalid args

    Dashes in double quoted arg detected as invalid args

    Having an string arg

        m_argParser.add_argument( "--user-origin")
                .default_value( std::string() )
                .help( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" );
    

    where the cli use is --user-origin="56.100000x27.000000mm" normally works fine.

    1. --user-origin="-56.100000x27.000000mm" where a dash is introduced inside the string, triggers an invalid arg parse error

    Changing the double quote to single quote --user-origin='-56.100000x27.000000mm' allows it to work

    Examining the argv in msvc, the double quotes do get stripped out by Windows but the arg format of --user-origin= remains

    image

    while the single quotes remain

    image

    1. In the case of the single quote case, argparse then returns everything after the equals sign to the .get() function, including the single quotes which seems kind of odd as well.

    I believe in python's argparse.

    Doing --user-origin="-21242" is valid form and solution to --user-origin "-21242" not working usually

    opened by marekr 0
  • Wrong text when no arguments supplied

    Wrong text when no arguments supplied

    If I require 3 positional arguments, but none are supplied, it always says "1 argument(s) expected. 0 provided.", rather than "3 arguments(s) expected..." It doesn't matter if you add ".required()" or not. This is confusing for the user. It would be better to simply not print this line, in fact - the help output is sufficient; prefixing it with this incorrect information is just confusing..

    opened by rnwhitehead 9
  • Add support for exclusive/dependant arguments

    Add support for exclusive/dependant arguments

    Some arguments are exclusive. Current workaround is to implement checks after the parsing like so :

    [...]
    program.parse_args(ac, av);
    
    if (program.is_used("--foo") && program.is_used("--bar")) {
        throw "--foo and --bar are exclusive !";
    }
    

    Furthermore, some parameters often require others to be present in order to be meaningfull. Once again, we currently need to check manualy that both are given.


    It would be nice to be able to use constructs like this :

    program.add_argument("--line").needs("--file");
    program.add_argument("--file").exclusive("--ip");
    program.add_argument("--ip"); // No need to specify again that they are exclusive
    program.add_argument("--port").needs("--ip").default_value(443);
    
    try {
      program.parse_args(ac, av);
    } catch (const std::runtime_error& err) {
      std::cerr << "Wrong arguments: " << err.what() << std::endl;
    }
    

    Usage :

    # Good
    ./program --file /tmp/file
    ./program --file /tmp/file --line 25
    ./program --ip 8.8.8.8
    ./program --ip 8.8.8.8 --port 80
    
    # Bad
    ./program --ip 8.8.8.8 --line 25
    ./program --line 25
    ./program --port 80
    ./program --file /tmp/file --port 80
    ./program --file /tmp/file --ip 8.8.8.8
    
    opened by f-michaut 0
Releases(v2.9)
  • v2.9(Sep 22, 2022)

    Thanks @ndevenish and @skrobinson

    • Added support for parse_known_args #201
    • Added -Wsign-conversion to the tests build and removed implicit conversion warnings #202
    • Allow --option=value form of arguments #203
    • Added -Wshadow and -Wconversion to CXX_FLAGS and fixed warnings #204
    • Added prefix_chars and assign_chars support for better option-value syntax #205
    • Improved help, metavar, subcommands, and samples #206
    Source code(tar.gz)
    Source code(zip)
  • v2.8(Sep 21, 2022)

    Subcommands

    Many programs split up their functionality into a number of sub-commands, for example, the git program can invoke sub-commands like git checkout, git add, and git commit. Splitting up functionality this way can be a particularly good idea when a program performs several different functions which require different kinds of command-line arguments. ArgumentParser now supports the creation of such sub-commands with add_subparser().

    #include <argparse/argparse.hpp>
    
    int main(int argc, char *argv[]) {
      argparse::ArgumentParser program("git");
    
      // git add subparser
      argparse::ArgumentParser add_command("add");
      add_command.add_argument("files")
        .help("Files to add content from. Fileglobs (e.g.  *.c) can be given to add all matching files.")
        .remaining();
    
      // git commit subparser
      argparse::ArgumentParser commit_command("commit");
      commit_command.add_argument("-a", "--all")
        .help("Tell the command to automatically stage files that have been modified and deleted.")
        .default_value(false)
        .implicit_value(true);
    
      commit_command.add_argument("-m", "--message")
        .help("Use the given <msg> as the commit message.");
    
      // git cat-file subparser
      argparse::ArgumentParser catfile_command("cat-file");
      catfile_command.add_argument("-t")
        .help("Instead of the content, show the object type identified by <object>.");
    
      catfile_command.add_argument("-p")
        .help("Pretty-print the contents of <object> based on its type.");
    
      // git submodule subparser
      argparse::ArgumentParser submodule_command("submodule");
      argparse::ArgumentParser submodule_update_command("update");
      submodule_update_command.add_argument("--init")
        .default_value(false)
        .implicit_value(true);
      submodule_update_command.add_argument("--recursive")
        .default_value(false)
        .implicit_value(true);
      submodule_command.add_subparser(submodule_update_command);
    
      // Add the subcommands to the parent parser
      program.add_subparser(add_command);
      program.add_subparser(commit_command);
      program.add_subparser(catfile_command);
      program.add_subparser(submodule_command);
    
      // Parse args
      try {
        program.parse_args(argc, argv);
      }
      catch (const std::runtime_error& err) {
        std::cerr << err.what() << std::endl;
        std::cerr << program;
        std::exit(1);
      }
    
      // Use arguments
    }
    
    [email protected]:/home/dev/$ ./git --help
    Usage: git [options] <command> [<args>]
    
    Optional arguments:
    -h --help    	shows help message and exits [default: false]
    -v --version 	prints version information and exits [default: false]
    
    Subcommands:
    add          	Add file contents to the index
    cat-file     	Provide content or type and size information for repository objects
    commit       	Record changes to the repository
    submodule    	Initialize, update or inspect submodules
    
    [email protected]:/home/dev/$ ./git add --help
    Usage: git add [options] files 
    
    Add file contents to the index
    
    Positional arguments:
    files        	Files to add content from. Fileglobs (e.g.  *.c) can be given to add all matching files.
    
    Optional arguments:
    -h --help    	shows help message and exits [default: false]
    -v --version 	prints version information and exits [default: false]
    
    [email protected]:/home/dev/$ ./git submodule --help
    Usage: git submodule [options] <command> [<args>]
    
    Initialize, update or inspect submodules
    
    Optional arguments:
    -h --help    	shows help message and exits [default: false]
    -v --version 	prints version information and exits [default: false]
    
    Subcommands:
    update       	Update the registered submodules to match what the superproject expects
    

    When a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages.

    Additionally, every parser has a .is_subcommand_used("<command_name>") member function to check if a subcommand was used.

    You can find relevant unit tests here.

    Source code(tar.gz)
    Source code(zip)
  • v2.7(Sep 18, 2022)

    • Added empty line above epilog #186
    • Update CI hosts and fix clang-cl build #189
    • Remove unnecessary back_inserter #191
    • Use references for any_cast #192
    Source code(tar.gz)
    Source code(zip)
  • v2.6(Jun 22, 2022)

    Merged pull request https://github.com/p-ranav/argparse/pull/125 - Improve nargs

    Thanks @hokacci

    You can now make a variable length list of arguments with the .nargs. Below are some examples.

    program.add_argument("--input_files")
      .nargs(1, 3);  // This accepts 1 to 3 arguments.
    

    Some useful patterns are defined like "?", "*", "+" of argparse in Python.

    program.add_argument("--input_files")
      .nargs(argparse::nargs_pattern::any);  // "*" in Python. This accepts any number of arguments including 0.
    
    program.add_argument("--input_files")
      .nargs(argparse::nargs_pattern::at_least_one);  // "+" in Python. This accepts one or more number of arguments.
    
    program.add_argument("--input_files")
      .nargs(argparse::nargs_pattern::optional);  // "?" in Python. This accepts an argument optionally.
    
    Source code(tar.gz)
    Source code(zip)
  • v2.5(May 27, 2022)

  • v2.4(Apr 20, 2022)

    • Fixed regression in version printing https://github.com/p-ranav/argparse/commit/3b89546fd09daf69458d8502b384ac536a3ec6b9
    • Updated doctest version from v2.3.5 to v2.4.8 https://github.com/p-ranav/argparse/commit/f56aec307fb441d3affcbef70875b397f8cd4156
    • Fixed unused argument warnings https://github.com/p-ranav/argparse/commit/5c5c55b83cc7d542890a47aeee6530a8ee6d10f7
    Source code(tar.gz)
    Source code(zip)
  • v2.3(Apr 2, 2022)

    • Improve thrown message in case of invalid argument - Now message contains information which argument is the source of error. It's easier to spot typo/understand which part of more complex command is the source of problem. https://github.com/p-ranav/argparse/commit/87afaba6ba3fca3e0e3c3aca9bebe0a94f294d25
    • Update cmake_minimum_required to 3.12.4
    • Update "Printing Help" documentation https://github.com/p-ranav/argparse/commit/5cceb98e3c1f5cf23d3323853062e4b59086381b
    • Updated README examples from exit() to std::exit() https://github.com/p-ranav/argparse/commit/8772b37aabf9c3679c6b346c113fc7b82a247452
    • Code cleanup - data structure names, initialization etc.
    Source code(tar.gz)
    Source code(zip)
  • v2.2(Sep 14, 2021)

    • Simplify parsing numeric arguments with .scan #65
    • Get arguments in optional with .present() #68
    • Simplify a few internals #71
    • Add the option to add text before and after help output #72
    • Avoid use of cmd.exe in Travis #77
    • Fix incorrect message when mUsedName is empty #79
    • Make ArgumentParser::add_*() functions working on the parser itself chainable #82
    • CMakeLists.txt : add export #86
    • Fix help if required and def-value. Fixes #89. #90
    • Show default value for arg in help message #92
    • nicer usage text for required arg #93
    • Qualify iterator functions #97
    • misc clean ups #98
    • Add Argument.append method to allow repeated argument use #99
    • Add ArgumentParser.is_used to discern user-supplied values from defaults #100
    • Allow user to limit version argument to --version #103
    • Added packaging using CPack and generation of pkg-config files. #107
    • Const-correct ArgumentParser #108
    • Fix std::min conflict with min/max definitions from windows.h #109
    • Replace size_t to std::size_t. #110
    • Some cleanup in CPack packaging #115
    • Document and use Argument.scan where possible #121
    Source code(tar.gz)
    Source code(zip)
  • v2.0(Nov 21, 2019)

    • Added support for gathering remaining arguments #17
    • Added support for actions without return values #39
    • Deprecated print_help() #40
    • Removed undocumented PARSE_ARGS macro #41
    • Added .clang-format #43
    • Switched to value semantics with #50 and #51
    • Switched to doctest and parallel builds #53
    • Arguments which start with '-' could be positional arguments #56
    Source code(tar.gz)
    Source code(zip)
    argparse.hpp(20.84 KB)
  • v1.9(Aug 17, 2019)

    • Support for required arguments: https://github.com/p-ranav/argparse/pull/33 and https://github.com/p-ranav/argparse/pull/34
    • Updated README for required arguments: https://github.com/p-ranav/argparse/issues/35
    Source code(tar.gz)
    Source code(zip)
  • v1.8(Jun 9, 2019)

  • v1.5(May 12, 2019)

  • v1.4(May 10, 2019)

  • v1.2(May 2, 2019)

  • v1.0(Apr 11, 2019)

    Argument Parser for Modern C++

    Highlights

    • Header-only library
    • Requires C++17
    • MIT License

    Quick Start

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

    #include <argparse.hpp>
    

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

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

    Argparse supports a variety of argument types including positional, optional, and compound arguments.

    Positional Arguments

    Here's an example of a positional argument:

    #include <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")
        .action([](const std::string& value) { return std::stoi(value); });
    
      program.parse_args(argc, argv);
      
      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. Inorder 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 .action method and provide a lambda function that tries 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);
    
    program.parse_args(argc, argv);
    
    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.

    Combining Positional and Optional Arguments

    argparse::ArgumentParser program("test");
    
    program.add_argument("square")
      .help("display the square of a given number")
      .action([](const std::string& value) { return std::stoi(value); });
    
    program.add_argument("--verbose")
      .default_value(false)
      .implicit_value(true);
    
    program.parse_args(argc, argv);
    
    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

    ArgumentParser.print_help() print 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
    

    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);
    
    program.parse_args(argc, argv);  // Example: ./main --input_files config.yml System.xml
    
    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 .action, 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})
      .action([](const std::string& value) { return std::stod(value); });
    
    program.parse_args(argc, argv);  // Example: ./main --query_point 3.5 4.7 9.2
    
    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})
      .action([](const std::string& value) { return std::stof(value); });
    
    program.parse_args(argc, argv);                    // Example: ./main -abc 1.95 2.47 
    
    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

    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 shared 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)
      .action([](const std::string& value) { return std::stoi(value); });
    
    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;
      });
    
    program.parse_args({"./test", "config.json"});
    
    nlohmann::json config = program.get<nlohmann::json>("config");
    

    Positional Arguments with Compound Toggle Arguments

    argparse::ArgumentParser program("test");
    
    program.add_argument("numbers")
      .nargs(3)
      .action([](const std::string& value) { return std::stoi(value); });
    
    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)
      .action([](const std::string& value) { return std::stof(value); });
    
    program.add_argument("--files")
      .nargs(3);
    
    program.parse_args(argc, argv);
    
    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 -abc 3.14 2.718 2 --files a.txt b.txt c.txt 3
    numbers = {1, 2, 3}
    a = true
    b = true
    c = {3.14, 2.718}
    d = {"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" };
      });
    
    program.parse_args(argc, argv);
    
    auto input = program.get("input");
    std::cout << input << std::endl;
    
    $ ./main fex
    baz
    

    Supported Compilers

    • GCC >= 7.0.0
    • Clang >= 4.0
    • MSVC >= 2017

    Contributing

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

    License

    The project is available under the MIT license.

    Source code(tar.gz)
    Source code(zip)
    argparse.hpp(25.13 KB)
Owner
Pranav
Pranav
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

Taylor C. Richberger 896 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

sailormoon 205 Oct 25, 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

André Müller 960 Nov 19, 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

Adi Shavit 1.1k Nov 21, 2022
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

Axel Souchet 92 Nov 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

Catch Org 649 Nov 6, 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: 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

null 2.4k Nov 17, 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

null 3.3k Nov 25, 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

Build Frameworks Group 378 Nov 4, 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

Erik Agsjö 7 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

Rebraws 1 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

Duckie 4 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

Zongzhi Chen 85 Nov 15, 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

The Washington Post 58 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

Enes Kaya ÖCAL 2 Dec 28, 2021
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

Ingo Wald 193 Sep 16, 2022
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

Daniele Pallastrelli 870 Nov 17, 2022
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

Pranav 2.2k Nov 19, 2022
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

Pranav 1.4k Nov 20, 2022