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

flags

Build Status

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

why

Other argument parsers are:

  • bloated
  • non-extensible
  • not modern
  • complicated

requirements

GCC 7.0 or Clang 4.0.0 at a minimum. This library makes extensive use of optional, nullopt, and string_view.

api

flags::args exposes three methods:

get

std::optional<T> get(const std::string_view& key) const

Attempts to parse the given key on the command-line. If the string is malformed or the argument was not passed, returns nullopt. Otherwise, returns the parsed type as an optional.

get (with default value)

T get(const std::string_view& key, T&& default_value) const

Functions the same as get, except if the value is malformed or the key was not provided, returns default_value. Otherwise, returns the parsed type.

positional

const std::vector<std::string_view>& positional() const

Returns all of the positional arguments from argv in order.

usage

Just include flags.h from the include directory into your project.

example

#include "flags.h"
#include <iostream>

int main(int argc, char** argv) {
  const flags::args args(argc, argv);

  const auto count = args.get<int>("count");
  if (!count) {
    std::cerr << "No count supplied. :(\n";
    return 1;
  }
  std::cout << "That's " << *count << " incredible, colossal credits!\n";

  if (args.get<bool>("laugh", false)) {
    std::cout << "Ha ha ha ha!\n";
  }
  return 0;
}
$ ./program
> No count supplied. :(
$ ./program --count=5 --laugh
> That's 5 incredible, colossal credits!
> Ha ha ha ha!

another example

#include "flags.h"
#include <iostream>
#include <string>

int main(int argc, char** argv) {
  const flags::args args(argc, argv);
  const auto& files = args.positional();
  const auto verbose = args.get<bool>("verbose", false);
  if (verbose) {
    std::cout << "I'm a verbose program! I'll be reading the following files:\n";
    for (const auto& file : files) {
      std::cout << "* " << file << '\n';
    }
  }
  // read files(files);
  return 0;
}
$ ./program /tmp/one /tmp/two /tmp/three --verbose
> I'm a verbose program! I'll be reading the following files: 
> * /tmp/one
> * /tmp/two
> * /tmp/three
$ ./program /tmp/one /tmp/two /tmp/three --noverbose
>%

extensions

flags simply uses the istream operator to parse values from argv. To extend the parser to support your own types, just supply an overloaded >>.

example

struct Date {
  int day;
  int month;
  int year;
};

// Custom parsing code.
std::istream& operator>>(std::istream& stream, Date& date) {
  return stream >> date.day >> date.month >> date.year;
}

int main(int argc, char** argv) {
  const flags::args args(argc, argv);
  if (const auto date = args.get<Date>("date")) {
    // Output %Y/%m/%d if a date was provided.
    std::cout << date->year << ":" << date->month << ":" << date->day << '\n';
    return 0;
  }
  // Sad face if no date was provided or if the input was malformed.
  std::cerr << ":(\n";
  return 1;
}
$ ./program --date="10 11 2016"
> 2016:11:10
$ ./program
> :(

command line details

flags's primary goal is to be simple to use for both the user and programmer.

key formatting

A key can have any number of preceding -s, but must have more than 0. The following are valid keys:

  • -key
  • --key
  • -------------key

value assignment

A value can be assigned to a key in one of two ways:

  • $ ./program --key=value
  • $ ./program --key value

bools

booleans are a special case. The following values make an argument considered false-y when parsed as a bool:

  • f
  • false
  • n
  • no
  • 0

If none of these conditions are met, the bool is considered true.

testing

flags uses both bfg9000 and mettle for unit-testing. After installing both bfg9000 and mettle, run the following commands to kick off the tests:

  1. 9k build/
  2. cd build
  3. ninja test

contributing

Contributions of any variety are greatly appreciated. All code is passed through clang-format using the Google style.

Owner
sailormoon
C++1z forever and always.
sailormoon
Comments
  • Allow values that begin with '-' (process them as both)

    Allow values that begin with '-' (process them as both)

    I have the need to pass negative integer values to an option in an application, hence this change.

    foo -bar -10

    will set the bar option to negative ten.

    foo -bar -10 -baz

    will set the bar option to negative ten and create a -10 option that is set "-baz". It's a little weird...

    This won't cause bugs with boolean options, since no value accepted as false starts with '-'.

  • Fix linking errors when including flags.h in more than one cpp file

    Fix linking errors when including flags.h in more than one cpp file

    the template specialization methods must be explicitly marked with inline, otherwise including flags.h twice will cause linker errors.

    Error LNK2005 "class std::optional<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > __cdecl flags::detail::get<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class std::unordered_map<class std::basic_string_view<char,struct std::char_traits<char> >,class std::optional<class std::basic_string_view<char,struct std::char_traits<char> > >,struct std::hash<class std::basic_string_view<char,struct std::char_traits<char> > >,struct std::equal_to<class std::basic_string_view<char,struct std::char_traits<char> > >,class std::allocator<struct std::pair<class std::basic_string_view<char,struct std::char_traits<char> > const ,class std::optional<class std::basic_string_view<char,struct std::char_traits<char> > > > > > const &,class std::basic_string_view<char,struct std::char_traits<char> > const &)" ([email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@[email protected][email protected][email protected]@[email protected]@@[email protected]@[email protected][email protected][email protected]@[email protected]@@[email protected]@@[email protected][email protected][email protected][email protected]@[email protected]@@[email protected]@@[email protected][email protected][email protected][email protected]@[email protected]@@[email protected]@@[email protected][email protected][email protected][email protected][email protected]@[email protected]@@[email protected]@[email protected][email protected][email protected]@[email protected]@@[email protected]@@[email protected]@[email protected]@@[email protected]@[email protected][email protected][email protected]@[email protected]@@[email protected]@Z) already defined in app.game-d.lib(appmain.obj) app.entry E:\repo\glmovement\.build\projects\app.game-d.lib(rendersystem.obj) 1

  • Add Support for CMake Builds

    Add Support for CMake Builds

    It is advantageous to package this project as a cmake-compatible module since we can then allow users to just add it to their existing build system. Note, this does not add cmake support for the test directory to keep the change set small.

    The cmake build system provided here supports an installation via cmake or working as a submodule. The docs have been updated to reflect this.

  • Add Positional Getters

    Add Positional Getters

    Since only options can be retrieved by the template get<T> functions, positional arguments needs to be manually parsed which added unneeded verbosity to the code.

    This pull request adds the following functions:

    • std::optional<T> args::get<T>(size_t positional_index)
    • T args::get<T>(size_t positional_index, , T&& default_value)

    If the positional_index doesn't exist an std::nullopt or the default value is returned.

    Also this pull request contains a fix for #8 and adds test cases for the aforementioned functions and fix.

  • Boolean options return false if no value was specified in the command line

    Boolean options return false if no value was specified in the command line

    Steps to reproduce:

    1. Copy the example to a file named src.cpp
    #include "flags.h"
    #include <iostream>
    
    int main(int argc, char** argv) {
      const flags::args args(argc, argv);
    
      const auto count = args.get<int>("count");
      if (!count) {
        std::cerr << "No count supplied. :(\n";
        return 1;
      }
      std::cout << "That's " << *count << " incredible, colossal credits!\n";
    
      if (args.get<bool>("laugh", false)) {
        std::cout << "Ha ha ha ha!\n";
      }
      return 0;
    }
    
    1. Add flags.h to the same folder.
    2. Compile using clang src.cpp -std=c++17 -o program.exe
    3. Run using .\program.exe --count 5 --laugh

    Expected result:

    That's 5 incredible, colossal credits!
    Ha ha ha ha!
    

    Actual result:

    That's 5 incredible, colossal credits!
    

    Environment:

    • OS: Windows 10
    • Compiler: Clang 9.0.0

    Reason behind the issue:

    template <>
    std::optional<bool> get(const argument_map& options,
                            const std::string_view& option) {
      if (const auto value = get_value(options, option)) {
        return std::none_of(falsities.begin(), falsities.end(),
                            [&value](auto falsity) { return *value == falsity; });
      }
      return std::nullopt;
    }
    

    In the aforementioned code, the function cannot differentiate between the two scenarios:

    1. .\program.exe --count 5 --laugh
    2. .\program.exe --count 5

    Since in both cases, args.get<bool>("laugh") will return std::nullopt.

    Suggested fix: Check if the option exists in the options map.

    template <>
    std::optional<bool> get(const argument_map& options,
                            const std::string_view& option) {
      if (const auto value = get_value(options, option)) {
        return std::none_of(falsities.begin(), falsities.end(),
                            [&value](auto falsity) { return *value == falsity; });
      }
      if (options.find(option) != options.end())
          return true;
      return std::nullopt;
    }
    
  • Remove `using std::experimental::{optional, nullopt, string_view}` from flags namespace.

    Remove `using std::experimental::{optional, nullopt, string_view}` from flags namespace.

    Out of laziness, and because std::experimental is such a long namespace, using std::experimental::{optional, nullopt, string_view} was used in the flags namespace. It should be removed when when both optional and string_view are moved into std proper.

  • Unit tests and Travis CI

    Unit tests and Travis CI

    1. Unit tests should be written using https://github.com/jimporter/mettle.
    2. There should be a Travis CI build/test ticker in the README after tests are added.
  • Adding multi values system

    Adding multi values system

    This is sorts of a quick and dirty change, but it allows for multiple options to be set:

    If this is passed on the command line:

    -foo=x -foo=y -foo=z
    

    Then args.values("foo") will return a vector with the values "x", "y", and "z".

    All other APIs are preserved and unchanged.

  • Argument validation + shortcuts

    Argument validation + shortcuts

    Now that there are some basic unit tests, flag validation and multiple arguments should be added.

    Currently thinking of a syntax similar to:

    const flags::args args(argc, argv);
    if (const auto opt = args.get_multiple<bool>("flag", "f", "no-flag", "other")) {
      const auto [argument, value] = *opt;
      // do something -- *argument will be the first of "flag", "f", or "no-flag" that matched
      // and *value will be its value.
    }
    

    for multiple arguments.

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
Argument Parser for Modern C++
Argument Parser for Modern C++

Highlights Single header file Requires C++17 MIT License Quick Start Simply include argparse.hpp and you're good to go. #include <argparse/argparse.hp

Nov 19, 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

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

Nov 21, 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

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

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

Nov 17, 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

Nov 4, 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

Sep 16, 2022
Small header only C++ library for writing multiplatform terminal applications

Terminal Terminal is small header only library for writing terminal applications. It works on Linux, macOS and Windows (in the native cmd.exe console)

Nov 18, 2022
Sep 22, 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

Nov 25, 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

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

Nov 3, 2022
This command-line tool converts an FM broadcast signal into stereo sound with de-emphasis applied.

stereodemux This command-line tool converts an FM broadcast signal into stereo sound with de-emphasis applied. It expects 16-bit signed-integer MPX (F

Nov 6, 2022