Skip to content

fbbdev/opt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OPT

opt is a bare-bones command line argument parsing library for C++14. It supports a non-standard key-value option style similar to the dd program from coreutils. Positional arguments and boolean flags are also supported. Numeric values can be followed by SI unit prefixes (e.g. 2.4k -> int: 2400, float: 2.4e+3). Clever usage of positional and keyword arguments can result in extremely readable command lines.

Supported types for options are bool, std::string, std::string_view, std::intmax_t, std::uintmax_t, float, double. Enum types and composite types std::complex<T>, std::array<T, N>, std::vector<T>, std::set<T>, are also supported, where T is one of the supported types.

Additional types can be supported by specializing the parse method of the Option class.

template<>
bool opt::Option<T>::parse(opt::StringView arg, std::ostream& err) {
    // arg is trimmed (no whitespace before and after content)

    return true; // when the option is not set (e.g. when arg is empty)

    error(err) << "report errors" << std::endl;
    return false; // on error

    value_ = /* parse value from arg */;

    set(); // option correctly set, value is valid
    return true; // no error
}

To parse command line arguments, call the opt::parse function. The function returns false on error, true on success.

bool opt::parse({ /* initializer-list of positional options */ },
                { /* initializer-list of keyword-only options */ },
                /* optional argument: reference to a
                   std::vector<opt::StringView> which
                   will contain ignored arguments */,
                argv, argv + argc,
                /* optional argument: reference to std::ostream
                   for error reporting. Default value is std::cerr */);

When the help flag is present on the command line, the parse function prints a simple usage message and returns false. The message can also be printed with the opt::usage function.

void opt::usage(opt::StringView program_name,
                { /* initializer-list of positional options */ },
                { /* initializer-list of keyword-only options */ },
                /* optional argument: reference to std::ostream
                   for usage message output. Default value is std::cerr */);

Example

See example/run.cpp for more details.

// run.cpp
#include "opt.hpp"

enum Mode {
    OneShot,
    Repeat,
};

template<>
const opt::Option<Mode>::value_map opt::Option<Mode>::values = {
    { "oneshot", OneShot },
    { "after", OneShot },
    { "repeat", Repeat },
    { "every", Repeat },
};

enum Unit {
    Second,
    Minute,
    Hour,
};

template<>
const opt::Option<Unit>::value_map opt::Option<Unit>::values = {
    { "seconds", Second },
    { "sec", Second },
    { "s", Second },
    { "minutes", Minute },
    { "m", Minute },
    { "hours", Hour },
    { "hr", Hour },
    { "h", Hour },
};

int main(int argc, char* argv[]) {
    using opt::Option;
    using opt::Placeholder;
    using opt::Required;

    Option<opt::StringView> cmd("cmd", Placeholder("COMMAND"), Required);
    Option<Mode> mode("mode", Required);
    Option<float> timeout("timeout", Placeholder("TIMEOUT"), Required);
    Option<Unit> unit("unit", Required);
    Option<bool> quiet("quiet", false);
    Option<bool> stop_on_error("stop_on_error", false);
    Option<float> until("until", Placeholder("TIME"), 0.0f);
    Option<std::uintmax_t> times("times", 0);

    if (!opt::parse({ cmd, mode, timeout, unit },
                    { quiet, stop_on_error, until, times },
                    argv, argv + argc))
        return -1;

    if (!cmd.is_set() || !mode.is_set() ||
            !timeout.is_set() || !unit.is_set()) {
        std::cerr << "error: required options are not set" << std::endl;
        opt::usage(argv[0],
                   { cmd, mode, timeout, unit },
                   { quiet, stop_on_error, until, times });
        return -1;
    }

    /* ... */

    return 0;
}

Compile and run:

# g++ -std=c++14 -o run run.cpp opt/opt.cpp -Iopt

# ./run help
Usage: ./run [help] [cmd=]COMMAND [mode=](oneshot|after|repeat|every)
  [timeout=]TIMEOUT [unit=](seconds|sec|s|minutes|m|hours|hr|h) [quiet]
  [stop_on_error] [until=TIME] [times=INT]

# ./run "echo hello" every 500m sec times=10 stop_on_error
... if implemented would print 'hello' every 500ms for 10 times ...