Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Argh! A minimalist argument handler.

License

NotificationsYou must be signed in to change notification settings

adishavit/argh

logo

Frustration-free command line processing

LanguageStandardLicenseTry it onlineBuild Status

So many different command line processing libraries out there and none of them just work!
Some bring their whole extended family of related and unrelated external dependencies (yes, I'm looking at you Boost).
Some require quirky syntax and/or very verbose setups that sacrifice simplicity for the generation of a cute usage message and validation. Many come to dominate yourmain() file and yet others do not build on multiple plaforms - for some even their own tests and trivial usage cause crashes on some systems.Argh!

If you're writing a highly-sophisticated command line tool, thenBoost.Program_options and its kind might give you many advanced options. However, if you need to get up and running quickly, effectively and with minimal fuss, give the single header-fileargh a try.

TL;DR

It doesn't get much simpler than this:

#include<iostream>#include"argh.h"intmain(int,char* argv[]){    argh::parsercmdl(argv);if (cmdl[{"-v","--verbose" }])        std::cout <<"Verbose, I am.\n";return EXIT_SUCCESS;}

TL;DR Videos

Philosophy

Contrary to many alternatives,argh takes a minimalistlaissez-faire approach, very suitable for fuss-less prototyping with the following rules:

The API is:

  • Minimalistic but expressive:
    • No getters nor binders
    • Just the[] and() operators
    • Easy iteration (range-for too)
  • You don't pay for what you don't use
  • Conversion to typed variables happens (viastd::istream >>) on the user sideafter the parsing phase
  • No exceptions thrown for failures
  • Liberal BSD license
  • Single header file
  • No non-std dependencies

argh doesnot care about:

  • How many '-' preceded your option
  • Which flags and options you support - that is your responsibility
  • Syntax validation:any command line is a valid (not necessarily unique) combination of positionalparameters,flags andoptions
  • Automatically producing a usage message

Tutorial

Create parser:

auto cmdl = argh::parser(argc, argv);

In fact, you can even dropargc. This will also work:

argh::parsercmdl(argv);

Positional argument access by (integer) index with[<size_t>]:

cout <<"Exe name is:" << cmdl[0] <<'\n';                               ^^^assert(cmdl[10000].empty());// out-of-bound index returns empty string            ^^^^^

Boolean flag argument access by (string) name with[<std::string>]:

cout <<"Verbose mode is" << ( cmdl["verbose"] ?"ON" :"OFF" ) <<'\n';                                    ^^^^^^^^^^^

Any dashes are trimmed so are not required.

Your flag can have several alternatives, just list them with[{ "<name-1>", "<name-2>", ... }]:

cout <<"Verbose mode is" << ( cmdl[{"-v","--verbose" }] ?"ON" :"OFF" ) <<'\n';                                    ^^^^^^^^^^^^^^^^^^^^^^^

Beyondbool andstd::string access with[], as shown above, we can also access the argument values as anstd::istream. This is very useful for type conversions.

std::istream positional argument access by (integer) index with(<size_t>):

std::string my_app_name;cmdl(0) >> my_app_name;// streaming into a string    ^^^cout <<"Exe name is:" << my_app_name <<'\n';

We can also check if a particular positional arg was given or not (this is like using[<std::string>] above):

if (!cmdl(10))  cerr <<"Must provide at least 10 arguments!" <<'\n';elseif (cmdl(11))  cout <<"11th argument  is:" << cmdl[11] <<'\n';

But we can also set default values for positional arguments. These are passed as the second argument:

float scale_factor;cmdl(2,1.0f) >> scale_factor;     ^^^^^^^

If the position argument was not given or the streaming conversion failed, the default value will be used.

Similarly, parameters can be accessed by name(s) (i.e. by string or list of string literals) with:
(<std::string> [, <default value>]) or({ "<name-1>", "<name-2>", ... } [, <default value>]):

float scale_factor;cmdl("scale",1.0f) >> scale_factor;// Use 1.0f as default value     ^^^^^^^^^^^^^float threshold;if (!(cmdl({"-t","--threshold"}) >> threshold))// Check for missing param and/or bad (inconvertible) param value  cerr <<"Must provide a valid threshold value! Got '" << cmdl("threshold").str() <<"'" << endl;else                                                                        ^^^^^^  cout <<"Threshold set to:" << threshold <<'\n';

As shown above, usestd::istream::str() to get the param value as astd:string or just stream the value into a variable of a suitable type. Standard stream state indicates failure, including when the argument was not given.
When using multiple names, the first value found will be returned.

Positional arguments can be iterated upon directly usingrange-for:

cout <<"Positional args:\n";for (auto& pos_arg : cmdl)  cout <<'\t' << pos_arg <<'\n';

Similarly,cmdl.size() will return the count ofpositional arguments.

Positional arguments, flagsand parameters are accessible as "ranges":

cout <<"Positional args:\n";for (auto& pos_arg : cmdl.pos_args())  cout <<'\t' << pos_arg <<'\n';cout <<"\nFlags:\n";for (auto& flag : cmdl.flags())  cout <<'\t' << flag <<'\n';cout <<"\nParameters:\n";for (auto& param : cmdl.params())  cout <<'\t' << param.first <<" :" << param.second <<'\n';

If a parameter appears several times in the command line, all its duplicates may be accessed, in order, like so:

cout <<"\nValues for all `--input` parameters:\n";for (auto& param : cmdl.params("input"))// iterate on all params called "input"  cout <<'\t' << param.first <<" :" << param.second <<'\n';

By default, options are assumed to be boolean flags.When this is not what you want, there are several ways to specify when an option is a parameter with an associated value.

  1. SpecifyPREFER_PARAM_FOR_UNREG_OPTION mode to interpretany<option> <non-option> as<parameter-name> <parameter-value>:

    usingnamespaceargh;auto cmdl = parser(argc, argv, parser::PREFER_PARAM_FOR_UNREG_OPTION);                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^cout << cmdl("--threshold").str() <<'\n';
  2. Pre-register an expected parameter name withadd_param() (before callingparse()):

    argh::parser cmdl;cmdl.add_param("threshold");// pre-register "threshold" as a param: name + valuecmdl.parse(argc, argv);cout << cmdl("threshold").str() <<'\n';

    You may alsobatch pre-register multiple options as parameters withadd_params({ ... }):

    argh::parser cmdl;cmdl.add_params({"-t","--threshold","-s","--scale" });// batch pre-register multiple params: name + valuecmdl.parse(argc, argv);cout << cmdl("threshold").str() <<'\n';

    Unregistered options will default to boolean flags.

  3. Since pre-registration has to be donebefore parsing, we might as well just use the ctor:

    argh::parsercmdl({"-t","--threshold","-s","--scale" });// batch pre-register multiple params: name + valuecmdl.parse(argc, argv);cout << cmdl("threshold").str() <<'\n';
  4. Use a= with no spaces around it within the option whencalling the app:

    >> my_app --threshold=4242

    This will automatically be interpreted as a named parameter-value pair.

Tips

  • By default, arguments of the form--<name>=<value> (with no spaces, one or more dashes), e.g.--answer=42, will be parsed as<parameter-name> <parameter-value>.To disable this specify theNO_SPLIT_ON_EQUALSIGN mode.
  • Specifying theSINGLE_DASH_IS_MULTIFLAG mode, a.k.aCompound Arguments, will split a single-hyphen argument into multiple single-character flags (as is common in various POSIX tools).
  • When usingSINGLE_DASH_IS_MULTIFLAG, you can still pre-register the last character as a param with the value, such that if we pre-registerf as a param,>> myapp -xvf 42 will be parsed with two boolean flagsx andv and a one paramf=42.
  • When parsing parameter values as strings that may contain spaces (e.g.--config="C:\Folder\With Space\Config.ini"), prefer using.str() instead of>> to avoid the default automatic whitespace input stream tokenization:
    cout << cmdl({ "-c", "--config" }).str().

Terminology

Any command line is composed of2 types ofArgs:

  1. Positional Args:
    Free standing, in-order, values
    e.g.config.json
  2. Options:
    Args beginning with- (and that are not negative numbers).
    We identify2 kinds ofOptions:
    1. Flags:
      Boolean options => (appear ? true : false)
      e.g.-v,--verbose
    2. Parameters:
      A named value followed by anon-option value
      e.g.--gamma 2.2

Thus, any command line can always be broken into some combination of(1) positional args(2) flags and(3) parameters.

API Summary

Parsing

Parse the command line using either

  • Theparse() method:parser::parse([argc,] argv [, mode]); or
  • The shorter form using the ctor directly:argh::parser([argc,] argv [, mode]);
  • The shortest form does not even requireargc, so in defaultmode just use:
    parser(argv);

Special Parsing Modes

Extra flexibility can be added by specifying parsing modes:

  • NO_SPLIT_ON_EQUALSIGN:By default, an option of the form--pi=22/7 will be parsed as aparameterpi with an associated value"22/7".By setting this mode, it will be not be broken at the=.
  • PREFER_FLAG_FOR_UNREG_OPTION:Split<option> <non-option> into<flag> and<pos_arg>.e.g.myapp -v config.json will havev as a lit flag andconfig.json as a positional arg.This is the default mode.
  • PREFER_PARAM_FOR_UNREG_OPTION:Interpret<option> <non-option> as<parameter-name> <parameter-value>.e.g.myapp --gamma 2.2 will havegamma as a parameter with the value "2.2".
  • SINGLE_DASH_IS_MULTIFLAG:Splits an option with asingle dash into separate boolean flags, one for each letter (a.k.aCompound Arguments).e.g. in this mode,-xvf will be parsed as 3 separate flags:x,v,f.

Argument Access

  • Usebracket operators to accessflags andpositional args:

    • Useoperator[index] to accessposition arg strings byindex:
      • e.g.assert(cmdl[0] == argv[0]), the app name.
    • Useoperator[string] to access booleanflags byname:
      • e.g.if (cmdl["v"]) make_verbose();
    • Useoperator[{...}] to access booleanflags bymultiple names:
      • e.g.if (cmdl[{ "v", "verbose" }]) make_verbose();
  • Use theparenthesis operators to get anstd::istream to stream values fromparameters andpositional args:

    • Useoperator(index) to access position argistream by index:
      • e.g.cmdl(0) >> my_app_name.
    • Useoperator(string) to accessparameter values byname:
      • e.g.cmdl("scale") >> scale_factor;
    • Useoperator({...}) to accessparameter values bymultiple names:
      • e.g.cmdl({ "-s", "--scale" }) >> scale_factor;
    • Useoperator(index, <default>) andoperator(string/{list}, <default>) to stream a default value if the arg did not appear on the command line:
      • e.g.cmdl("scale", 1.0f) >> scale_factor;

The streaming happens at the user's side, so conversion failure can be checked there:e.g

if (!(cmdl("scale") >> scale_factor))  cerr <<"Must provide valid scale factor!" <<'\n';

Use the.str() method to get the parameter value as a string: e.g.cmdl("name").str();

More Methods

  • Useparser::add_param(),parser::add_params() or theparser({...}) constructor tooptionally pre-register a parameter name when inPREFER_FLAG_FOR_UNREG_OPTION mode.
  • Useparser,parser::pos_args(),parser::flags() andparser::params() to access and iterate over the Arg containers directly.

Finding Argh!

  • copyargh.h somewhere into your projects directories
  • or include the repository as asubmodule
  • or useCMake!

Finding Argh! - CMake

The providedCMakeLists.txt generates targets for tests, a demo application and an install target to installargh system-wide and make it known to CMake.You can control generation of testand exampletargets using the optionsBUILD_TESTS andBUILD_EXAMPLES. Onlyargh alongside its license and readme will be installed - not tests and demo!

Addargh to your CMake-project by using

find_package(argh)

The package exportsarghINTERFACE library target andargh_INCLUDE_DIR variable. Makeargh.h known to your compiler by using one of the following methods; both will make the location ofargh.h known to the compiler, not link in a precompiled library - even when usingtarget_link_libraries().

target_include_directories(${MY_TARGET_NAME}PRIVATE"${argh_INCLUDE_DIR}")#ORtarget_link_libraries(${MY_TARGET_NAME} argh)

Additional Build Systems

Buck

Buck support:

Run the example:

buck run :example

Run the tests:

buck run :testsbuck run test_package

If you takeargh as a submodule, then the visible target is//:argh.

Colophon

I ❤ your feedback.
If you found Argh! useful - do Tweet about it to letme know.
If you found it lacking, please post anissue.

Packages

No packages published

Contributors27

Languages


[8]ページ先頭

©2009-2026 Movatter.jp