Skip to content

wlodzislav/args

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Modern C++ Command Line Arguments Library

Modern C++ arguments parsing library with beautiful API. Single header. Inspired by commander.js.

Supports all fundamental types and most of the standart containers. Could be used with custom value types and containers.

Short API Example:

auto b = false;
auto i = 0;
auto d = 0.0;
std::string str = ""s;
auto v = std::vector<int>{};
auto m = std::map<std::string, std::string>{};

args::options options = {
	{"-b", &b},
	{"-i", &i},
	{"-d", &d},
	{args::required, "-s", "--str", &str},
	{"-v", &v},
	{"-m", &m}
};

args::parse(argc, argv, options);

See short-syntax.cpp for the full example.

Chain API Example:

auto b = false;
auto i = 0;
auto d = 0.0;
auto str = ""s;
auto v = std::vector<int>{};
auto m = std::map<std::string, std::string>{};

auto p = args::parser{}
	.option("-b", &b)
	.option(args::required, "-i", &i)
	.option("-d", &d)
	.option("-s", "--str", &str)
	.option(args::required, "-v", "--vector", &v)
	.option("-m", "--map", &m);

auto cmd_called = false;
auto cmd_b = false;
auto e = ""s;
p.command("cmd", "c")
	.option("-b", &cmd_b)
	.option("-e", &e)
	.action([&]() {
		cmd_called = true;
	});

p.parse(argc, argv);

See chain-syntax.cpp for the full example.

With autogenerated help:

auto a = ""s;
auto b = ""s;
auto c = ""s;
auto d = ""s;

auto carg1 = ""s;
auto crest = std::vector<std::string>{};
args::parser p = args::parser{}
	.name("cli-cmd")
	.description("Some text")
	.command_required()
	.option("-a", "Global option A", &a)
	.option("-b", "--bb", "Global option B", &b);

p.command("list", "l", "List command")
	.arg(args::required, "carg1", "List command arg1", &carg1)
	.rest("crest", "List command rest args", &crest)
	.option("-c", "Option C", &c)
	.option(args::required, "-d", "--dd", "Option D", &d);

p.command("get", "g", "Get command")
	.arg(args::required, "smt", "What to get", &carg1)
	.option("-h", "How to get", &c);

p.parse(argc, argv);

See help.cpp for the full example.

Short API:

Chain API:

Custom help generation:

Features

  • Commands
  • Multi-word commands
  • Global/command options
  • Repeated options
  • Global/command positional args
  • Capture global/command rest positional args in container
  • Required options, args, rest args
  • Require command to be called
  • Autogenerates --help documentation + for commands
  • Build-in error messages for invalid/required options, arguments, commands
  • Supports non conventional options: -frtti, -fno-rtti, +fb
  • Supports pairs key=value as option value
  • Supports any type that could be parsed with std::stringstream
  • 1, 0, true, false, on, off, yes, no values for bool flags
  • Implicitly add --no-flag for bool flags
  • Supports --
  • Supports std::vector-like containers for repeated options
  • Supports std::pair for key=value option value
  • Supports std::map-like containers for repeated key=value option value
  • Any value could be passed to lambda

Exceptions handling

To output default error messages wrap parse(...) in:

try {
	p.parse(argc, argv);

} catch (const std::runtime_error& err) {
	std::cout << err.what() << std::endl;
	std::exit(1);
}
To handle all errors separately wrap `parse(...)` in:
try {
	p.parse(argc, argv);

} catch (const args::invalid_option& err) {
	// when unregistered option is passed
	// use err.option

} catch (const args::invalid_command_option_value& err) {
	// when failed to parse command option value
	// use err.command, err.option and err.value

} catch (const args::invalid_option_value& err) {
	// when failed to parse option value
	// use err.option and err.value

} catch (const args::invalid_command_arg_value& err) {
	// when failed to parse command argument value
	// use err.command, err.arg and err.value

} catch (const args::invalid_arg_value& err) {
	// when failed to parse argument value
	// use err.arg and err.value

} catch (const args::unexpected_arg& err) {
	// when non captured arguments is passed
	// use err.value

} catch (const args::missing_command_option& err) {
	// only when there are required command options
	// use err.command and err.option

} catch (const args::missing_option& err) {
	// only when there are required options
	// use err.option

} catch (const args::missing_command_arg& err) {
	// only when there are required command arguments
	// use err.command and err.arg

} catch (const args::missing_arg& err) {
	// only when there are required arguments
	// use err.arg

} catch (const args::missing_command& err) {
	// only when parser.command_required() is called

}

See errors.cpp, required-errors.cpp and command-required-error.cpp for the full error handling examples.

See make examples output for all errors messages.

Generated help

See help.cpp, required-command-help.cpp examples.

For using parts of the generated help for the custom help output see custom-help.cpp example.

args::parse(argv, argc, options) #

Used for short syntax.

void parse(int argc, const char** argv, const args::options& ptions);

args::option{...} #

Used for short syntax.

args::option{[args::required], name, destination_ptr);
args::option{[args::required], short_name, long_name, destination_ptr);
  • [args::required] args::required_t Set optional marker to make option required
  • name std::string Short -s, long --long or non conventional +fb, -fno-rtti
  • short_name std::string Short -s
  • long_name std::string Long --long
  • destination_ptr T* Set option value by pointer

All overloads example:

auto b = false;
args::options options = {
	{"-b", &b},
	{"-b", "Description", &b},
	{args::required, "-b", &b}
	{args::required, "-b", "Description", &b}
	{"-b", "--long", &b},
	{"-b", "--long", "Description", &b},
	{args::required, "-b", "--long", &b}
	{args::required, "-b", "--long", "Description", &b}
};
All overloads:
template<typename T>
args::option(const std::string& name, T* destination);

template<typename T>
args::option(args::required_t, const std::string& name, T* destination);

template<typename T>
args::option(const std::string& short_name, const std::string& long_name, T* destination);

template<typename T>
args::option(args::required_t, const std::string& short_name, const std::string& long_name,
	T* destination);

args::options #

Used for short syntax.

using args::options = std::vector<option>;

args::parser{} #

parser.name(name) #

Set program name for documentation.

parser& name(const std::string& name);

parser.description(description) #

Set program description for documentation.

parser& description(const std::string& description);

parser.command_required() #

If called will throw when no command is called.

parser& command_required();

parser.option(...) #

parser.option([args::required], name, [description], destination_ptr);
parser.option<Value_Type>([args::required], name, [description], lambda);
parser.option([args::required], short_name, long_name, [description], destination_ptr);
parser.option<Value_Type>([args::required], short_name, long_name, [description], lambda);

Specify global options.

  • [args::required] args::required_t Set optional marker to make option required
  • name std::string Short -s, long --long or non conventional +fb, -fno-rtti
  • short_name std::string Short -s
  • long_name std::string Long --long
  • description std::string Description used in help generation
  • destination_ptr T* Set option value by pointer
  • lambda void (T) Get option value with lambda

Note! When using lambda first template parameter Value_Type is required.

All overloads example:

auto b = false;
auto p = parser{}
	// using destination_ptr
	.option("-s", &b)
	.option("-s", "Description", &b)
	.option(args::required, "-s" &b)
	.option(args::required, "-s", "Description", &b)
	.option("-s", "--long", &b)
	.option("-s", "--long", "Description", &b)
	.option(args::required, "-s", "--long", &b)
	.option(args::required, "-s", "--long", "Description", &b)

	// non conventional options with destination_ptr
	.option("+fw-tf", &b)
	.option("+fw-tf", "Description", &b)
	.option(args::required, "+fw-tf" &b)
	.option(args::required, "+fw-tf", "Description", &b)

	// using lambda
	.option<bool>("-s", [&](auto v) { b = v; })
	.option<bool>("-s", "Description", [&](auto v) { b = v; })
	.option<bool>(args::required, "-s" [&](auto v) { b = v; })
	.option<bool>(args::required, "-s", "Description", [&](auto v) { b = v; })
	.option<bool>("-s", "--long", [&](auto v) { b = v; })
	.option<bool>("-s", "--long", "Description", [&](auto v) { b = v; })
	.option<bool>(args::required, "-s", "--long", [&](auto v) { b = v; })
	.option<bool>(args::required, "-s", "--long", "Description", [&](auto v) { b = v; })

	// non conventional options with lambda
	.option("+fw-tf", [&](auto v) { b = v; })
	.option("+fw-tf", "Description", [&](auto v) { b = v; })
	.option(args::required, "+fw-tf" [&](auto v) { b = v; })
	.option(args::required, "+fw-tf", "Description", [&](auto v) { b = v; });
All overloads
template<typename T>
args::parser& option(const std::string& name, T* destination);

template<typename T>
args::parser& option(args::required_t, const std::string& name, T* destination);

template<typename T, typename F>
args::parser& option(const std::string& name, F handler);

template<typename T, typename F>
args::parser& option(args::required_t, const std::string& name, F handler);

template<typename T>
args::parser& option(const std::string& short_name, const std::string& long_name_or_desc,
	T* destination);

template<typename T>
args::parser& option(const std::string& short_name, const std::string& long_name,
	const std::string& description, T* destination);

template<typename T>
args::parser& option(args::required_t, const std::string& short_name,
	const std::string& long_name_or_desc, T* destination);

template<typename T>
args::parser& option(args::required_t, const std::string& short_name, const std::string& long_name,
	const std::string& description, T* destination);

template<typename T, typename F>
args::parser& option(const std::string& short_name, const std::string& long_name_or_desc,
	F handler);

template<typename T, typename F>
args::parser& option(const std::string& short_name, const std::string& long_name,
	const std::string& description, F handler);

template<typename T, typename F>
args::parser& option(args::required_t, const std::string& short_name,
	const std::string& long_name_or_desc, F handler);

template<typename T, typename F>
args::parser& option(args::required_t, const std::string& short_name,
	const std::string& long_name, const std::string& description, F handler);

parser.arg(...) #

parser.arg(destination_ptr);
parser.arg<Value_Type>(lambda);
parser.arg([args::required], name, [description], destination_ptr);
parser.arg<Value_Type>([args::required], name, [description], lambda);

Specify global positional arguments.

When arguments are passed before command name they are treated as global. If command arguments are already captured or command has no arguments all subsequent arguments will be treated as global.

  • [args::required] args::required_t Set optional marker to make option required
  • name std::string Name used in required errors and help generation
  • description std::string Description used in help generation
  • destination_ptr T* Set option value by pointer
  • lambda void (T) Get option value with lambda

Note! When using lambda first template parameter Value_Type is required.

All overloads example:

auto arg = ""s;
auto p = parser{}
	// using destination_ptr
	.arg(&arg)
	.arg("file", &arg)
	.arg("file", "Description", &arg)
	.arg(args::required, "file", &arg)
	.arg(args::required, "file", "Description", &arg)

	// using lambda
	.arg([&](auto v) { arg = v; })
	.arg("file", [&](auto v) { arg = v; })
	.arg("file", "Description", [&](auto v) { arg = v; })
	.arg(args::required, "file", [&](auto v) { arg = v; })
	.arg(args::required, "file", "Description", [&](auto v) { arg = v; })
All overloads
template<typename T>
parser& arg(T* destination);

template<typename T>
parser& arg(const std::string& name, T* destination);

template<typename T>
parser& arg(const std::string& name, const std::string& description, T* destination);

template<typename T>
parser& arg(args::required_t, const std::string& name, T* destination);

template<typename T>
parser& arg(args::required_t, const std::string& name, const std::string& description,
	T* destination);

template<typename T, typename F>
parser& arg(F handler);

template<typename T, typename F>
parser& arg(const std::string& name, F handler);

template<typename T, typename F>
parser& arg(const std::string& name, const std::string& description, F handler);

template<typename T, typename F>
parser& arg(args::required_t, const std::string& name, F handler);

template<typename T, typename F>
parser& arg(args::required_t, const std::string& name, const std::string& description,
	F handler);

parser.rest(...) #

parser.rest(destination_ptr);
parser.rest<Value_Type>(lambda);
parser.rest([args::required], name, [description], destination_ptr);
parser.rest<Value_Type>([args::required], name, [description], lambda);

Capture all the rest positional arguments in the container.

  • [args::required] args::required_t Set optional marker to make option required
  • name std::string Name used in required errors and help generation
  • description std::string Description used in help generation
  • destination_ptr T* Set option value by pointer
  • lambda void (T) Get option value with lambda

Note! When using lambda first template parameter Value_Type is required.

All overloads example:

auto rest = std::vector<std::string>{};
auto p = parser{}
	// using destination_ptr
	.rest(&rest)
	.rest("cmd", &rest)
	.rest("cmd", "Description", &rest)
	.rest(args::required, "cmd", &rest)
	.rest(args::required, "cmd", "Description", &rest)

	// using lambda
	.rest([&](auto v) { rest = v; })
	.rest("cmd", [&](auto v) { rest = v; })
	.rest("cmd", "Description", [&](auto v) { rest = v; })
	.rest(args::required, "cmd", [&](auto v) { rest = v; })
	.rest(args::required, "cmd", "Description", [&](auto v) { rest = v; })
All overloads
template<typename T>
parser& rest(T* destination);

template<typename T>
parser& rest(const std::string& name, T* destination);

template<typename T>
parser& rest(const std::string& name, const std::string& description, T* destination);

template<typename T>
parser& rest(args::required_t, const std::string& name, T* destination);

template<typename T>
parser& rest(args::required_t, const std::string& name, const std::string& description,
	T* destination);

template<typename T, typename F>
parser& rest(F handler);

template<typename T, typename F>
parser& rest(const std::string& name, F handler);

template<typename T, typename F>
parser& rest(const std::string& name, const std::string& description, F handler);

template<typename T, typename F>
parser& rest(args::required_t, const std::string& name, F handler);

template<typename T, typename F>
parser& rest(args::required_t, const std::string& name

parser.command(...) #

parser.command(name, [alias], [description], [destination_ptr]);

Declare command. Returns command instance that could be used to set commands options, arguments and action.

  • name std::string Command name
  • alias std::string Command alias
  • description std::string Description used in help generation
  • destination_ptr bool* Set to true if command is called

Note! When called with only 2 string arguments alias must be single word and description must be multiple words.

All overloads example:

auto command_called = false;
auto p = parser{};

// with destination_ptr
p.command("list", &command_called);

p.command("list", "Description must be multi word", &command_called);

p.command("list all", "la", &command_called);

p.command("list", "l", "Description", &command_called);

// with action
p.command("list")
	.action([]() { /* do smt */ });

p.command("list", "Description must be multi word")
	.action([]() { /* do smt */ });

p.command("list all", "la")
	.action([]() { /* do smt */ });

p.command("list", "l", "Description")
	.action([]() { /* do smt */ });
All overloads
command_internal& command(const std::string& name);

command_internal& command(const std::string& name, const std::string& alias_or_desc);

command_internal& command(const std::string& name, const std::string& alias,
	const std::string& description);

command_internal& command(const std::string& name, bool* destination);

command_internal& command(const std::string& name, const std::string& alias_or_desc,
	bool* destination);

command_internal& command(const std::string& name, const std::string& alias,
	const std::string& description, bool* destination);

command.option(...) #

Same as parser.option(...) except it returns command instance.

All overloads
template<typename T>
command_internal& option(const std::string& name, T* destination);

template<typename T>
command_internal& option(args::required_t, const std::string& name, T* destination);

template<typename T, typename F>
command_internal& option(const std::string& name, F handler);

template<typename T, typename F>
command_internal& option(args::required_t, const std::string& name, F handler);

template<typename T>
command_internal& option(const std::string& short_name, const std::string& long_name_or_desc,
	T* destination);

template<typename T>
command_internal& option(const std::string& short_name, const std::string& long_name,
	const std::string& description, T* destination);

template<typename T>
command_internal& option(args::required_t, const std::string& short_name,
	const std::string& long_name_or_desc, T* destination);

template<typename T>
command_internal& option(args::required_t, const std::string& short_name,
	const std::string& long_name, const std::string& description, T* destination);

template<typename T, typename F>
command_internal& option(const std::string& short_name,
	const std::string& long_name_or_desc, F handler);

template<typename T, typename F>
command_internal& option(const std::string& short_name, const std::string& long_name,
	const std::string& description, F handler);

template<typename T, typename F>
command_internal& option(args::required_t, const std::string& short_name,
	const std::string& long_name_or_desc, F handler);

template<typename T, typename F>
command_internal& option(args::required_t, const std::string& short_name,
	const std::string& long_name, const std::string& description, F handler);

command.arg(...) #

Same as parser.arg(...) except it returns command instance.

All overloads
template<typename T>
command_internal& arg(T* destination);

template<typename T>
command_internal& arg(const std::string& name, T* destination);

template<typename T>
command_internal& arg(const std::string& name, const std::string& description, T* destination);

template<typename T>
command_internal& arg(args::required_t, const std::string& name, T* destination);

template<typename T>
command_internal& arg(args::required_t, const std::string& name, const std::string& description,
	T* destination);

template<typename T, typename F>
command_internal& arg(F handler);

template<typename T, typename F>
command_internal& arg(const std::string& name, F handler);

template<typename T, typename F>
command_internal& arg(const std::string& name, const std::string& description, F handler);

template<typename T, typename F>
command_internal& arg(args::required_t, const std::string& name, F handler);

template<typename T, typename F>
command_internal& arg(args::required_t, const std::string& name, const std::string& description,
	F handler);

command.rest(...) #

Same as parser.rest(...) except it returns command instance.

All overloads
template<typename T>
command_internal& rest(T* destination);

template<typename T>
command_internal& rest(const std::string& name, T* destination);

template<typename T>
command_internal& rest(const std::string& name, const std::string& description, T* destination);

template<typename T>
command_internal& rest(args::required_t, const std::string& name, T* destination);

template<typename T>
command_internal& rest(args::required_t, const std::string& name, const std::string& description,
	T* destination);

template<typename T, typename F>
command_internal& rest(F handler);

template<typename T, typename F>
command_internal& rest(const std::string& name, F handler);

template<typename T, typename F>
command_internal& rest(const std::string& name, const std::string& description, F handler);

template<typename T, typename F>
command_internal& rest(args::required_t, const std::string& name, F handler);

template<typename T, typename F>
command_internal& rest(args::required_t, const std::string& name, const std::string& description,
	F handler);

command.action(lambda) #

Call lambda if command is called. Is called after all options and arguments are parsed.

  • lambda void () Call if command is called
command_internal& action(std::function<void (void)> action);

Example:

auto p = parser{};

p.command("list")
	.action([]() { /* do smt */ });

parser.parse(argv, argc) #

Parse options and arguments.

Throws exceptions for invalid options and arguments, unexpected arguments, missing required options, arguments and commands.

  • argv, argc From main() arguments
void parse(int argc, const char** argv);

Exception: args::invalid_option #

When unregistered option is passed.

Subclass std::runtime_error

Properties:

  • option std::string

Exception: args::invalid_option_value #

When failed to parse option value.

Subclass std::runtime_error

Properties:

  • option std::string
  • value std::string

Exception: args::invalid_command_option_value #

When failed to parse command option value.

Subclass args::invalid_option_value

Properties:

  • command std::string
  • option std::string
  • value std::string

Exception: args::invalid_arg_value #

When failed to parse argument value.

Subclass std::runtime_error

Properties:

  • arg std::string
  • value std::string

Exception: args::invalid_command_arg_value #

When failed to parse command argument value.

Subclass args::invalid_arg_value

Properties:

  • command std::string
  • arg std::string
  • value std::string

Exception: args::unexpected_arg #

When non captured arguments is passed.

Subclass std::runtime_error

Properties:

  • value std::string

Exception: args::missing_command #

When command is required but not passed.

Subclass std::runtime_error

Properties:

  • command std::string

Exception: args::missing_option #

When option is required but not passed.

Subclass std::runtime_error

Properties:

  • option std::string

Exception: args::missing_command_option #

When command option is required but not passed.

Subclass args::missing_option

Properties:

  • command std::string
  • option std::string

Exception: args::missing_arg #

When positional argument is required but not passed.

Subclass std::runtime_error

Properties:

  • arg std::string

Exception: args::missing_command_arg #

When command positional argument is required but not passed.

Subclass args::missing_arg

Properties:

  • command std::string
  • arg std::string

parser.help(lambda) #

Custom --help handler.

If not present will output generated documentation.

See custom-help.cpp example.

  • lambda void () Call if --help present
template<typename F>
parser& help(F help_fun);

parser.format_help([indent]) -> str #

Return generated documentation.

  • indent std::string Use as indentation for help
std::string format_help(const std::string& indentation = default_indentation);

parser.format_command_help(command_name, [indent]) -> str #

Return generated documentation for command.

  • command_name std::string Name of alias of the command
  • indent std::string Use as indentation for help
std::string format_command_help(const std::string& command_name,
	const std::string& indentation = default_indentation);

parser.format_usage([indent]) -> str #

Return generated usage section.

  • indent std::string Use as indentation for help
std::string format_usage(const std::string& indentation = default_indentation);

parser.format_args([indent]) -> str #

Return generated arguments section.

  • indent std::string Use as indentation for help
std::string format_args(const std::string& indentation = default_indentation);

parser.format_options([indent]) -> str #

Return generated options section.

  • indent std::string Use as indentation for help
std::string format_options(const std::string& indentation = default_indentation);

parser.format_commands([indent]) -> str #

Return generated commands section.

  • indent std::string Use as indentation for help
std::string format_commands(const std::string& indentation = default_indentation);

parser.format_command_usage(command_name, [indent]) -> str #

Return generated command usage section.

  • command_name std::string Name of alias of the command
  • indent std::string Use as indentation for help
std::string format_command_usage(const std::string& command_name,
	const std::string& indentation = default_indentation);

parser.format_command_args(command_name, [indent]) -> str #

Return generated command args section.

  • command_name std::string Name of alias of the command
  • indent std::string Use as indentation for help
std::string format_command_args(const std::string& command_name,
	const std::string& indentation = default_indentation);

parser.format_command_options(command_name, [indent]) -> str #

Return generated command options section.

  • command_name std::string Name of alias of the command
  • indent std::string Use as indentation for help
std::string format_command_options(const std::string& command_name,
	const std::string& indentation = default_indentation);

About

Modern C++ Command Line Arguments Library

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published