Code Monkey home page Code Monkey logo

args's People

Contributors

bitc avatar darealshinji avatar dhmemi avatar iamthebot avatar ivan-v-kush avatar kolanich avatar mapaydar avatar milipili avatar mtnviewjohn avatar nbdy avatar njlr avatar olivierldff avatar pysco68 avatar rholais avatar scotthutchinson avatar taywee avatar travisdowns avatar zhihaoy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

args's Issues

Add macros to get version

args.hxx is missing a macro like ARGS_VERSION to get the version at compile time. A triplet ARGS_VERSION_MAJOR, ARGS_VERSION_MINOR and ARGS_VERSION_PATCH could be even better.

It could be useful for logs, for example.

Allow inclusion into multiple source files

Currently you get a "multiple definition" error when linking two source files that include args.hxx. The affected functions are:

std::string::size_type Glyphs(const std::string &string_)
std::vector<std::string> Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0)
std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser)

I resolved the error by making them inline or static, but I don't have much experience with header only libraries, so it may not be the best solution.

Nargs support

I see some Nargs class in the code, but not the documentation. Is it supported / maintained?

Disallow multiple arguments for a the same value flag

args::ValueFlag<int> integer(parser, "integer", "The integer flag", {'i'});
./program -i4 -i5

In this example the value at integer is set to 5. How can I make it an error to disallow such behaviour? I.e. only allow the -i flag to be passed once. Same issue with args::Flag too.

Make help text "'--' can be used to terminate..." optional

The following help text entry is not optional if you have both options and arguments

      "--" can be used to terminate flag options and force all following
      arguments to be treated as positional options

The offending piece of code

if (hasoptions && hasarguments)
{
  for (const std::string &item: Wrap(std::string("\"") + terminator + "\" can be used to terminate flag options and force all following arguments to be treated as positional options", helpParams.width - helpParams.flagindent))
  {
    help << std::string(helpParams.flagindent, ' ') << item << '\n';
  }
}

Consider making this help text optional. (For my use-case, it is not possible to use. It just makes noise)

Unable to chain positional lists

Hi,

First, thanks for your great lib !

Unless i misunderstood usage, i did not find a way to chain positional lists as documented in "Long descriptions and proper wrapping and listing".

Indeed, the first positional list grab all next parameters event using the "--" delimiter.

Here is my code :

	args::ArgumentParser parser("This is a test program with a really long description that is probably going to have to be wrapped across multiple different lines.  This is a test to see how the line wrapping works", "This goes after the options.  This epilog is also long enough that it will have to be properly wrapped to display correctly on the screen");
	args::HelpFlag help(parser, "HELP", "Show this help menu.", { 'h', "help" });
	args::ValueFlag<std::string> foo(parser, "FOO", "The foo flag.", { 'a', 'b', 'c', "a", "b", "c", "the-foo-flag" });
	args::ValueFlag<std::string> bar(parser, "BAR", "The bar flag.  This one has a lot of options, and will need wrapping in the description, along with its long flag list.", { 'd', 'e', 'f', "d", "e", "f" });
	args::ValueFlag<std::string> baz(parser, "FOO", "The baz flag.  This one has a lot of options, and will need wrapping in the description, even with its short flag list.", { "baz" });
	args::Positional<std::string> pos1(parser, "POS1", "The pos1 argument.");
	args::PositionalList<std::string> poslist1(parser, "POSLIST1", "The poslist1 argument.");
	args::Positional<std::string> pos2(parser, "POS2", "The pos2 argument.");
	args::PositionalList<std::string> poslist2(parser, "POSLIST2", "The poslist2 argument.");

	parser.ParseArgs(std::vector<std::string>{"pos1", "foo", "bar", "--" , "pos2","baz"});

	auto a = args::get(pos1);
	auto b = args::get(poslist1);
	auto c = args::get(pos2);
	auto d = args::get(poslist2);

poslist1 contains now {"foo" ,"bar" , "pos2" , "baz"}

Cheers,
S.

Implicit values

It would be nice to have implicit values for flags like -j[N] in make.

I know they are mentioned in readme:

It will not ever:

  • Allow one value flag to take a specific number of values (like --foo first second, where --foo slurps both arguments). You can instead split that with a flag list (--foo first --foo second) or a custom type extraction ( --foo first,second)
  • Allow you to have value flags only optionally accept values

Is it because of the technical difficulties? I have working implementation, but it requires some incompatible changes in interfaces (ValueFlagBase::ParseValue for instance). Usage is simple:

ImplicitValueFlag<int> foo("foo", "foo", implicitValue, defaultValue);
// or: ImplicitValueFlag<int> foo("foo", "foo", defaultValue);
// or: ImplicitValueFlag<int> foo("foo", "foo");

Will you accept such PR?

Using Windows like "/" short prefixes don't work

When trying to use Windows like "/" short prefixes via "parser.ShortPrefix("/")" such short options don't work or can't be matched. Using this kind of flags or value flags for short options ( /h /v /i ... etc.) don't work:

> test.exe /h
Flag could not be matched: h
  test.exe {OPTIONS}

    This is a test program.

  OPTIONS:

      /h, /help                         display this help section
      /v, /version                     show the program version
      /longopt                         use longopt opt
      * Required arguments: *
      /i[file], /input:[file]           the input file to deal with
      /o[file], /output:[file]       the resulting output file

These also don't work: /i [file] /o [file]

Further I think if such Windows like setable short options "/" would work, they would at least for short value flags /x:[value], also probably need to offer a setable short seperator ":" in order to be somehow slightly more Windows conform and distinguishable as an short flag with a value argument.

include guards

Including the header multiple times results in redefinition warnings. Can we add either a #pragma once at the top or use a standard include guard? Can submit a PR if necesary but it's a one-liner.

Edit: definitely not a one liner. What's the point of the different test namespace abusing macros like that?

Sub group validation not working as expected

I've created a group and a subgroup which has an AllOrNone validator (see example below). I expect that I must specify either all -a -b -c flags or none as arguments. This is not the case. I can specify one or more.

cpp    args::ArgumentParser parser("This is a test program.", "This goes after the options.");
    args::Group group (parser, "Group:", args::Group::Validators::DontCare);
    args::Group subgroup (group, "SubGroup:", args::Group::Validators::AllOrNone);
    args::Flag aflag(subgroup, "a", "test flag", {'a'});
    args::Flag bflag(subgroup, "b", "test flag", {'b'});
    args::Flag cflag(subgroup, "c", "test flag", {'c'});

If I make the make the change below (set subgroup parent as parser), then it works. Is this a bug?

cpp    args::ArgumentParser parser("This is a test program.", "This goes after the options.");
    args::Group group (parse, "SubGroup:", args::Group::Validators::AllOrNone);
    args::Flag aflag(subgroup, "a", "test flag", {'a'});
    args::Flag bflag(subgroup, "b", "test flag", {'b'});
    args::Flag cflag(subgroup, "c", "test flag", {'c'});

Default arguments, ValueFlagList and reset

Hi,

when I initialize a ValueFlagList with default arguments these defaults are reset when parsing the arguments.
Is it possible to circumvent this?

Thanks in advance!

-Wunused-parameter warnings

A small request from me.
It'd be nice if args.hxx didn't generate warnings about unused parameters.

Ideally, it'd also avoid -Wshadow warnings, but this option is probably not that popular.

$ g++-6 -Wall -Wextra test.cxx -I.
In file included from test.cxx:16:0:
./args.hxx: In member function ‘virtual std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > args::Base::GetDescription(const string&, const string&, const string&, const string&) const’:
./args.hxx:400:92: warning: unused parameter ‘shortPrefix’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                            ^~~~~~~~~~~
./args.hxx:400:124: warning: unused parameter ‘longPrefix’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                                                            ^~~~~~~~~~
./args.hxx:400:155: warning: unused parameter ‘shortSeparator’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                                                                                           ^~~~~~~~~~~~~~
./args.hxx:400:190: warning: unused parameter ‘longSeparator’ [-Wunused-parameter]
  virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                                                                                                                   ^~~~~~~~~~~~~
./args.hxx: In member function ‘virtual std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > args::NamedBase::GetDescription(const string&, const string&, const string&, const string&) const’:
./args.hxx:436:92: warning: unused parameter ‘shortPrefix’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                            ^~~~~~~~~~~
./args.hxx:436:124: warning: unused parameter ‘longPrefi’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                            ^~~~~~~~~
./args.hxx:436:154: warning: unused parameter ‘shortSeparator’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                          ^~~~~~~~~~~~~~
./args.hxx:436:189: warning: unused parameter ‘longSeparator’ [-Wunused-parameter]
   virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                                                   ^~~~~~~~~~~~~
./args.hxx: In member function ‘virtual std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > args::FlagBase::GetDescription(const string&, const string&, const string&, const string&) const’:
./args.hxx:516:155: warning: unused parameter ‘shortSeparator’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                           ^~~~~~~~~~~~~~
./args.hxx:516:190: warning: unused parameter ‘longSeparator’ [-Wunused-parameter]
  virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                                                   ^~~~~~~~~~~~~
./args.hxx: In static member function ‘static bool args::Group::Validators::DontCare(const args::Group&)’:
./args.hxx:636:51: warning: unused parameter ‘group’ [-Wunused-parameter]
                 static bool DontCare(const Group &group)
                                                   ^~~~~
./args.hxx: In static member function ‘static bool args::Group::Validators::CareTooMuch(const args::Group&)’:
./args.hxx:641:54: warning: unused parameter ‘group’ [-Wunused-parameter]
                 static bool CareTooMuch(const Group &group)
                                                      ^~~~~
In file included from test.cxx:16:0:
./args.hxx: In member function ‘bool args::ValueReader<std::__cxx11::basic_string<char> >::operator()(const string&, const string&, std::__cxx11::string&)’:
./args.hxx:1567:44: warning: unused parameter ‘name’ [-Wunused-parameter]
         bool operator()(const std::string &name, const std::string &value, std::string &destination)
                                            ^~~~
test.cxx: In member function ‘void DoublesReader::operator()(const string&, const string&, std::tuple<double, double>&)’:
test.cxx:297:40: warning: unused parameter ‘name’ [-Wunused-parameter]
     void operator()(const std::string &name, const std::string &value, std::tuple<double, double> &destination)
                                        ^~~~
test.cxx: In member function ‘void ToLowerReader::operator()(const string&, const string&, std::__cxx11::string&)’:
test.cxx:424:40: warning: unused parameter ‘name’ [-Wunused-parameter]
     void operator()(const std::string &name, const std::string &value, std::string &destination)
                                        ^~~~
In file included from test.cxx:576:0:
./args.hxx: In member function ‘virtual std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > argstest::Base::GetDescription(const string&, const string&, const string&, const string&) const’:
./args.hxx:400:92: warning: unused parameter ‘shortPrefix’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                            ^~~~~~~~~~~
./args.hxx:400:124: warning: unused parameter ‘longPrefix’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                                                            ^~~~~~~~~~
./args.hxx:400:155: warning: unused parameter ‘shortSeparator’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                                                                                           ^~~~~~~~~~~~~~
./args.hxx:400:190: warning: unused parameter ‘longSeparator’ [-Wunused-parameter]
  virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const
                                                                                                                                                                                   ^~~~~~~~~~~~~
./args.hxx: In member function ‘virtual std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > argstest::NamedBase::GetDescription(const string&, const string&, const string&, const string&) const’:
./args.hxx:436:92: warning: unused parameter ‘shortPrefix’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                            ^~~~~~~~~~~
./args.hxx:436:124: warning: unused parameter ‘longPrefi’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                            ^~~~~~~~~
./args.hxx:436:154: warning: unused parameter ‘shortSeparator’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                          ^~~~~~~~~~~~~~
./args.hxx:436:189: warning: unused parameter ‘longSeparator’ [-Wunused-parameter]
   virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefi, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                                                   ^~~~~~~~~~~~~
./args.hxx: In member function ‘virtual std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > argstest::FlagBase::GetDescription(const string&, const string&, const string&, const string&) const’:
./args.hxx:516:155: warning: unused parameter ‘shortSeparator’ [-Wunused-parameter]
             virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                           ^~~~~~~~~~~~~~
./args.hxx:516:190: warning: unused parameter ‘longSeparator’ [-Wunused-parameter]
  virtual std::tuple<std::string, std::string> GetDescription(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator) const override
                                                                                                                                                                                   ^~~~~~~~~~~~~
./args.hxx: In static member function ‘static bool argstest::Group::Validators::DontCare(const argstest::Group&)’:
./args.hxx:636:51: warning: unused parameter ‘group’ [-Wunused-parameter]
                 static bool DontCare(const Group &group)
                                                   ^~~~~
./args.hxx: In static member function ‘static bool argstest::Group::Validators::CareTooMuch(const argstest::Group&)’:
./args.hxx:641:54: warning: unused parameter ‘group’ [-Wunused-parameter]
                 static bool CareTooMuch(const Group &group)
                                                      ^~~~~
In file included from test.cxx:576:0:
./args.hxx: In member function ‘bool argstest::ValueReader<std::__cxx11::basic_string<char> >::operator()(const string&, const string&, std::__cxx11::string&)’:
./args.hxx:1567:44: warning: unused parameter ‘name’ [-Wunused-parameter]
         bool operator()(const std::string &name, const std::string &value, std::string &destination)
                                            ^~~~
./args.hxx: In instantiation of ‘bool argstest::ValueReader<T>::operator()(const string&, const string&, T&) [with T = int; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
./args.hxx:1600:21:   required from ‘void argstest::ValueFlag<T, Reader>::ParseValue(const string&) [with T = int; Reader = argstest::ValueReader<int>; std::__cxx11::string = std::__cxx11::basic_string<char>]’
test.cxx:635:1:   required from here
./args.hxx:1540:45: warning: unused parameter ‘name’ [-Wunused-parameter]
         bool operator ()(const std::string &name, const std::string &value, T &destination)

Group validation doesn't work in Subparser

#include <iostream>
#include <args.hxx>

int main(int argc, char **argv) {
  args::ArgumentParser parser("This is a test program.");
  args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
  args::Group commands(parser, "commands");

  args::Command solve(
      commands, "solve", "you know", [&](args::Subparser &parser) {
        args::Group required(parser, "", args::Group::Validators::All);
        args::Positional<std::string> file(required, "file",
                                           "This file is required");
        parser.Parse();
        std::cout << "File input: " << args::get(file) << std::endl;
      });
  try {
    parser.ParseCLI(argc, argv);
  } catch (args::Help) {
    std::cout << parser;
    return 0;
  } catch (args::Error e) {
    std::cerr << e.what() << std::endl;
    std::cerr << parser;
    return 1;
  }
  return 0;
}

a.exe solve
File input:
^ empty string

I have workaround because I only have one positional flag, so I can use args::Options::Required, but still want to know whether this should work.

Sub arguments (git like)

How to share flag with several flags?
Let's say I have Add and Init which except array of strings how can I declare it in one place and reuse it in Add or in Init

Thank you

Get position of matched argument

I am looking to implement a command based utility, which will use a master args parser
and then delegate the remaining arguments to a sub-parser.

The project states that it will never support flag arguments sensitive to order.

My use-case is as follows:
./prog --help
shall display the master arg parser help.

./prog COMMAND --help
should show the COMMAND arg parser help.
Since it appears it will not be a goal to support positional/conditional flag arguments,
I suggest adding an index position on the detected argument. That way, I can do the following:

catch (args::Help)
{
  if (command && args::position (help) > args::position (command))
    continue;

  ...
}

and thus delegate further processing to the command handler.

Use of uninitialised value (allowJoinedLongValue)

There is a circular reference with allowJoinedLongValue and longseparator attributes in methods LongSeparator and SetArgumentSeparations (both called by ArgumentParser constructor).

LongSeparator uses allowJoinedLongValue (not initialized at this point), and allowJoinedLongValue is initialized only in SetArgumentSeparations (but it uses longseparator initialized in the previous method).

I've seen this using Valgrind. This is the Valgrind's output (PS: it's not the current args.hxx version but the problem is still there):
==22686== Conditional jump or move depends on uninitialised value(s)
==22686== at 0x414E4D: args::ArgumentParser::LongSeparator(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) (args.hxx:2097)
==22686== by 0x414AA6: args::ArgumentParser::ArgumentParser(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&, std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) (args.hxx:2040)
==22686== by 0x408CB3: main (myclass.cpp:1095)
==22686== Uninitialised value was created by a stack allocation
==22686== at 0x408C17: main (myclass.cpp:1094)

A way to exclude an option from help output

Is there any way to indicate that an option should be excluded from help output? Based on a quick scan of the code it seems like there isn't.

It is useful for "internal" flags that shouldn't be seen by the end user (for example, I have a script that launches the process with some internal flag set indicating that the process should return a value to the script, but an end-user shouldn't care about this flag).

The workaround I'm using now is to create a Group call with_help, a child of the real ArgumentParser and add arguments that should show help there, and internal arguments directly to the root parser, like this:

    args::ArgumentParser true_parser{"hidden-parser - this description won't show up anywhere"};
    args::Group with_help{parser};

    // public args
    args::HelpFlag help{with_help, "help", "Display this help menu", {'h', "help"}};
    args::Flag public_arg1{with_help, "public-arg1", "Help for arg1", {"arg1"}};
    args::Flag public_arg1{with_help, "public-arg1", "Help for arg1", {"arg1"}};

    // private args
    args::Flag public_arg1{true_parser, "hidden-arg1", "", {"hidden-arg1"}};

Now when I want to output I create a dummy/temporary new ArgumentParser and add the with_args child group to it:

    args::ArgumentParser help_parser("some-application: help goes here");
    help_parser.Add(with_help);
    std::cerr << help_parser;

Maybe that's already the best way?

get full original command line (full argv[]) within a command function

Is there currently an easy way to pull out the full original command line string that was used to invoke the program (essentially what argv was) from within a Command/subparser with the current API? I use the commands interface, and have a separate function that is invoked for subcommands. Within a subcommand, I want to be able to get the full command line to be able to print it out to a log file that gets created based on the input args to the program. Is there a way to do this right now that I'm just missing?

Parse known args but ignore unknown ones?

Can the following be achieved by this library?

In my main() function, I want to check against "some" arguments, namely -i thefile.img, but want to ignore others, namely --gtest-xyz, as the latter will later be parsed/extraced by GoogleTest.

While GoogleTest has it's own argument parsing code, I dislike to write my own argument parser for my main() function. What I could do is adding all GoogleTest specific arguments to the parser in my main function... but that seems a bit brittle, hence I'm looking for a better solution.

I'm totally aware that this is not the standard use case for argument parser libraries... nevertheless, my hope is that this library can help me with this. Maybe I could write my own Matcher? Any hints?

noexcept warning in Visual Studio 2019

This kind of function may not throw. Declare it 'noexcept' (f.6). 460

                Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {}

            Matcher(Matcher &&other) : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags))

add copy constructors and/or move semantics to support modern C++ auto expresions

I'd love to write this:

    auto parser = args::ArgumentParser(
        "Benchmark a BFS graph search on a knureon complex"
    );

    auto help = args::HelpFlag(
        parser,
        "help",
        "Display this help menu",
        {'h', "help"}
    );

    auto args::ValueFlag<uint32_t>(
        parser,
        "seed",
        "The seed to initialize the random number generator",
        {"seed"}
    );

    auto scale = args::ValueFlag<uint32_t>(
        parser,
        "scale",
        "The logarithm base two of the number of vertices",
        {'s', "scale"}
    );

    auto edgefactor = args::ValueFlag<uint32_t>(
        parser,
        "edgefactor",
        "The ratio of the graph’s edge count to its vertex count",
        {'e', "edgefactor"}
    );

as I find it easier to read and encourages the use of auto everywhere.

Wrapper for ARGS in a settings manager class

Hi,

I'm facing some issues trying to create a settings manager for my application based on ARGS (and I really love this library).

This is the code I'm working on (settingsmanager.h) :

#ifndef SETTINGSMANAGER_H
#define SETTINGSMANAGER_H

/*
 * Includes
 */
#include "args.hxx"
#include <unordered_map>

class SettingsManager
{
public:

    enum class eSetting {
        flagA,
        flabB,
        flagC,
        valueFlagA, // str
        valueFlagB // str
        valueFlagC // int
    };
    
    SettingsManager();
    ~SettingsManager(void);
    
    bool Initialize(int argc, char **argv);
    
    // -------
    // AWFUL CODE
            template<typename T>
    T get(eSetting setting) {
        switch(setting) {
            case eSetting::flagA:
            case eSetting::flagB:
            case eSetting::flagC:
            {
                args::Flag* flag = static_cast<args::Flag*>(*(settingsMap_.at(setting)));
                return args::get(*flag);
                break;
            }
            case eSetting::valueFlagA:
            case eSetting::valueFlagB:
            {
                args::ValueFlag<std::string>* flag = static_cast<args::ValueFlag<std::string>*>(*(settingsMap_.at(setting)));
                return args::get(*flag);
                break;
            {
            case eSetting::valueFlagC:
            {
                args::ValueFlag<int>* flag = static_cast<args::ValueFlag<int>*>(*(settingsMap_.at(setting)));
                return args::get(*flag);
                break;
            }
            default:
                return false;
                break;
        }
    }
    // ------
    
    /*
    // What kind of code I would like...
    template<typename T>
    T get(eSetting setting) {
        return args::get(*settingsMap.at(setting));
    }
    */
    
private:

    static args::ArgumentParser cliParser_;
    static args::Flag flagA_;
    static args::Flag flagB_;
    static args::Flag flagC_;
    static args::ValueFlag<std::string> valueFlagA_;
    static args::ValueFlag<std::string> valueFlagB_;
    static args::ValueFlag<int> valueFlagC_;

    std::unordered_map<eSetting, args::FlagBase*> settingsMap_;
};

#endif // SETTINGSMANAGER_H

I would like a generic get method that can return any type (string, int, double).
The rest of my app is supposed to know only the enum eSetting (not ARGS namespace).

Is it possible ? Which is the syntax for such template function ?
Should I review my conception to let ARGS management only in the main ?

Thx for help

Add possible values to help output for MapFlag

For MapFlag is it possible to get the list of possible values added to the help output? For example:

enum class Example {
  X,
  Y,
  Z
};
std::unordered_map<std::string, Example> exampleMapValues{
  {'thexoption', Example::X},
  {'theyoption', Example::Y},
  {'thezoption', Example::Z}
};
args::MapFlag<std::string, Example> exampleFlag(
  arguments, "mv", "A description", { 'm', "mapvalue" }, exampleMapValues);

Currently results in help output (for that option) of:

      -m[mv], --mapvalue=[mv]           A description

If the possible values could be automatically added to the help output, something along the lines of:

      -m[mv], --mapvalue=[mv]           A description
                                        One of: thexoption, theyoption, thezoption

Would save a lot of effort on behalf of users, and possible mistakes in forgetting to add/remove values. The information is already there as well, encoded in the unordered_map.

Prefix and postfix text in command usage string

Enable the ability to add additional text before and after usage text.
Currently, my master argument parser looks like this.

 prog {OPTIONS} [COMMAND]

I would like it to look like this

 prog {OPTIONS} [COMMAND] [<args>]

even tho the [<args>] bit is not backed up by any args from the master parser.

When the command parser gets a --help, i want the usage text to say

prog COMMAND {OPTIONS} [X] [Y] ......

This requires the disabling of the auto-appended argv[0] argument, and replace it with a string of my choice.

[GCC 8] error: catching polymorphic type by value

I ran into this problem while compiling my project with gcc 8 today.
myproject/args.hxx:1764:34: error: catching polymorphic type ‘class args::SubparserError’ by value [-Werror=catch-value=] catch (args::SubparserError) ^~~~~~~~~~~~~~
I compiled with the flag -Werror which triggered the error.

Multiple definitions during link

Hi!
Using the header from multiple source files results in link errors. Are the missing inline statements on purpose or by accident? Great library, thanks for it!

Only the First Element of ValueFlagList gets parsed.

As the title says, only the first element of ValueFlagList seems to get parsed, see the reproducer below.

% g++ ValueFlagTest.cxx -g
% ./a.out --www more than one word
terminate called after throwing an instance of 'args::ParseError'
  what():  Passed in argument, but no positional arguments were ready to receive it: than
zsh: abort (core dumped)  ./a.out --www more than one word

I looked into and it seems that only a single word is given to ValueFlagList::ParseValues:

% gdb --args a.out -w eins zwei drei
gdb) b args.hxx:3621
Breakpoint 1 at 0x429904: file args.hxx, line 3621.
(gdb) run
Starting program: /home/jonas/valueflagtest/a.out -w eins zwei drei
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.31-2.fc32.x86_64

Breakpoint 1, args::ValueFlagList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, args::detail::vector, args::ValueReader>::ParseValue (this=0x7fffffffd210, 
    values_=std::vector of length 1, capacity 1 = {...}) at args.hxx:3621
3621	                values.insert(std::end(values), v);
Missing separate debuginfos, use: dnf debuginfo-install libgcc-10.1.1-1.fc32.x86_64 libstdc++-10.1.1-1.fc32.x86_64
(gdb) p values
$1 = std::vector of length 0, capacity 0
(gdb) p values_
$2 = std::vector of length 1, capacity 1 = {"eins"}

shouldn't values_ contain {"eins", "zwei", "drei"}?

Reproducer:

#include <iostream>

#include "args.hxx"

int main(int argc, char* argv[]) {
  args::ArgumentParser parser("Test of the ValueFlagList class");
  args::ValueFlagList<std::string> words(parser, "words", "words words words...", {'w', "www"});
  args::HelpFlag help(parser, "help", "show this help and exit", {'h', "help"});

  try {
    parser.ParseCLI(argc, argv);
  } catch (args::Help&) {
    std::cerr << parser << std::endl;
    return 0;
  }

  for (const auto& word : words) {
    std::cout << word << std::endl;
  }

  return 0;

}

Change name of the project

I assume you never expected this library to become so popular and just went with the most straight forward name. Unfortunately that makes it really hard to find community resources using search engines, because they see it as a generic programming keyword. Your username is really easy to recognize though, so maybe you can make that part of the project name.

However that's just a suggestion and there certainly are many arguments against a name change.

From where did you obtained catch.hpp

Hi,
I'm currently busy to package args for Debian since it is a precondition for some projects of the Debian Med team. The Debian ftpmaster has rejected the code since it is not clear how the file catch.hpp was generated. I've searched the internet for this file but had no real luck to find the source - just other instances of that file are used in several other projects.
So could you please enlighten me where to download the real source and how the file was generated?
Kind regards, Andreas.

Conditional args ?

Depending on a parent option value, is it possible to make children options required or not? (other than by adding additional checks after ArgumentParser::ParseCLI)

Required positional argument

I read through the guide and couldn't find anything on required positional arguments. For example:

./program {OPTIONS} <file> 

Here <file> would be a positional argument that must appear somewhere in the arguments.

Better value parsing

Two general parsing issues that should be easy to address:

  1. "7" and " 7" parse as valid integers but "7 " and " 7 " do not.
  2. there are many string-like things besides std::string that have space breaking extraction problems, such as std::filesystem::path.

This is how I did it in dimcli:

template <typename T> 
bool Cli::stringTo(T & out, const std::string & src) const {
    // versions of stringTo_impl taking ints as extra parameters are
    // preferred (better conversion from 0), if they don't exist for T 
    // (because no out=src assignment operator exists) then the versions 
    // taking longs are considered.
    return stringTo_impl(out, src, 0, 0);
}

template <typename T>
auto Cli::stringTo_impl(T & out, const std::string & src, int, int) const
    -> decltype(out = src, bool()) 
{
    out = src;
    return true;
}

template <typename T>
auto Cli::stringTo_impl(T & out, const std::string & src, int, long) const
    -> decltype(std::declval<std::istringstream &>() >> out, bool()) 
{
    m_interpreter.clear();
    m_interpreter.str(src);
    if (!(m_interpreter >> out) || !(m_interpreter >> std::ws).eof()) {
        out = {};
        return false;
    }
    return true;
}

template <typename T>
bool Cli::stringTo_impl(
    T & /* out */, const std::string & /* src */, long, long
) const {
    // In order to parse an argument there must be one of:
    //  - assignment operator for std::string to T
    //  - istream extraction operator for T
    //  - parse action attached to the Opt<T> instance that doesn't call
    //    opt.parseValue(), such as opt.choice().
    assert(false && "no assignment from string or stream extraction operator");
    return false;
}

Memory Corruption with clang-cl

Hi,

I've encountered a weird bug when using args with clang-cl on Windows, in release mode only. Using Visual Studio 2019 debugger, I suspect a memory corruption. Here is the code:

#include "args.hpp"

#include <iostream>

inline auto to_argv(std::vector<std::string>& v)
{
	auto r = std::vector<char*>{};
	for (auto& e : v)
		r.emplace_back(e.data());
	r.emplace_back(nullptr);
	return r;
}

auto other_main(int argc, char* argv[]) -> int
{
	std::cerr << argc << std::endl;
	for(auto i = 0; i < argc; ++i)
		std::cerr << argv[i] << std::endl;
	auto parser = args::ArgumentParser{ "Command Line" };
	auto const help = args::HelpFlag{ parser, "help", "Display this help menu", {'h', "help"} };
	try
	{
		parser.ParseCLI(argc, argv);
	}
	catch (const args::Help&)
	{
	}
	return 0;
}

int main(int argc, char* argv[])
{
	auto const commands = std::vector<std::string>
	{
		"command",
		"command_2",
	};
	for (auto const& command : commands)
	{
		auto _args = std::vector<std::string>
		{
			command,
			"-h",
		};
		for (auto const& a : _args)
			std::cerr << a << std::endl;
		auto args = to_argv(_args);
		other_main(static_cast<int>(args.size()) - 1, args.data());
	}
}

This should print:

command
-h
2
command
-h
command_2
-h
2
command_2
-h

which it does in debug (or with MSVC or clang on Linux), but it prints:

command
-h
2
command
-h
command_2

2
command_2
-h

In other cases I tested, it prints rubbish, or simply crashes. I attached the whole self-contained sample, with example cmake commands.
args_bug.zip

Q: How to setup an optional throwable version flag and other required group flags together...?

I somehow stumbled about the following here. - I wanted to have an optional -v | --version flag, just for printing out a program version, which works let's say similar like accessing the "-h | --help" output text mechanism (help exception output). and then exits the program.

But when I also define together a required group of value flags as to be "all" validated, a usual/normal optional flag like "-v" will never be executed, instead only always the text "Group validation failed somewhere!" output of the parser together with the help output is shown.

See this:

args::ArgumentParser parser("This is a test program.", "Example: test -i file -o file");
args::HelpFlag help(parser, "help", "display this help section", {'h', "help"});
args::Flag version(parser, "version", "show the program version", {'v', "version"});

args::Group filegroup(parser, "* Required arguments: *", args::Group::Validators::All);
args::ValueFlag<std::string> input(filegroup, "file", "the input file to deal with", {'i', "input"});
args::ValueFlag<std::string> output(filegroup, "file", "the resulting output file", {'o', "output"});

try
    {
        parser.ParseCLI(argc, argv);
    }
    catch (args::Help)
    {
        std::cout << parser;
        return 0;
    }
    catch (args::ParseError e)
    {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return 1;
    }
    catch (args::ValidationError e)
    {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return 1;
    }
    if (version) { std::cout << " test v.1.0 - Copyright (c) 2017 by Testcorp" << std::endl; exit(0); }
    if (input) { inputFilename = args::get(atninput); }
    if (output) { outputFilename = args::get(atnoutput); }
    ...
    ...

Invoking the program with "./test -v" or "./test --version" gives always only

"Group validation failed somewhere!"
...help text...

So how would one handle an optional version flag setup, which behaves here like the "-h | --help" optional and allows to throw and print out just some message text and then exit, without giving out instead the parser group validation output ("Group validation failed somewhere!") together with the help text?

excluding options

Is it possible to make some options exclude or exclusive to each other and otherwise throw an exception?

For example --now can only be used if --open or --close was given and --open and --close cannot be used together.

SIGSEGV with args::ArgumentParser inside a class

Hi, i'm getting a SIGSEGV when calling args::ArgumentParser::ParseCLI().
Context:
args::ArgumentParser is a private member of some class.
An instance of args::HelpFlag is created on the constructor body, and the instance of args::ArgumentParser is passed as first parameter.
The crash occurs when I call args::ArgumentParser::ParseCLI() from the args::ArgumentParser instance in another function.

The following snippet should reproduce the problem:

#include "args.hxx"


class MyClass{
args::ArgumentParser parser;

public:	
	MyClass(const char* description = "A description", 
			const char* notes = "Some notes"):
		parser(description, notes)
	{
		args::HelpFlag help(parser, "help", "lala", {'h', "help"}); 
		//If I comment out the previous line the problem dissapears
	}

	void operator()(int argc, const char **argv){
		parser.ParseCLI(argc, argv);
	
	}


};

int main(int argc, const char *argv[])
{
	MyClass myobj; 
 	
	myobj(argc, argv); //SIGSEGV!!
	return 0;
}

and here's a dump of (part of) the Valgrind output:

==18241==    at 0x405446: args::Group::Reset() (in /tmp/X/test/using_args)
==18241==    by 0x4092E0: __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > args::ArgumentParser::ParseArgs<__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >(__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >) (in /tmp/X/test/using_args)
==18241==    by 0x40774A: decltype (begin({parm#1})) args::ArgumentParser::ParseArgs<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) (in /tmp/X/test/using_args)
==18241==    by 0x405A3E: args::ArgumentParser::ParseCLI(int, char const* const*) (in /tmp/X/test/using_args)
==18241==    by 0x40627D: MyClass::operator()(int, char const**) (in /tmp/X/test/using_args)
==18241==    by 0x402BC4: main (in /tmp/X/test/using_args)
==18241==  Address 0x28 is not stack'd, malloc'd or (recently) free'd
==18241== 
==18241== 
==18241== Process terminating with default action of signal 11 (SIGSEGV)
==18241==  Access not within mapped region at address 0x28

Feature request: set those args which are matched to 0

In args::parse_args, rather than parsing const char** argv , parse char** argv and set those argv entries to null if they are matched.

Furthermore, in ParseCLI, only populate the std::vector<std::string> args vector with entries in argv which are not null.

With both suggestions, we can start nesting parsers. For example we parse a first set of flags, then go to the next set of flags depending on the result of the first parser, using the remaining non-null argv arguments.

Making it faster (although you shouldn't care)

I enjoyed your benchmark, and args was about ~15% faster than dimcli, but when I reduced the loop to just the parse call and asserts it was 30% slower. This is entirely because creating an istringstream object takes a long time, if you did something like make it a member of ValueReader and just call ss.clear(); ss.str(value); for each parse you'll go 20-40% faster overall - yes, it makes that much of a difference.

Required Flags

Hi,

Is there a simple way to mark things as required or mandatory? I've seen #4, but putting required flags in a group is OK, except, as you point out, the error message is not ideal.

No way to get parse error message in ARGS_NOEXCEPT mode

When using this library in ARGS_NOEXCEPT mode, there is no way to get the detailed error message.

When the user enters an incorrect command line, then the best we can do is print "Parse Error", instead of the more detailed parse error message.

spdlog_ex's can throw exception

You should not store std::string in the spdlog_ex class, because the std::move in the constructor can throw an exception and also rethrowing the spdlog_ex exception will try to copy the _msg which can also throw an exception.

Getting a Map as parse result

Is there a way to get a Map or List<pair> with the parsed values so that you can use it in another class to process the params..?

I can't find it..

Command parsing

Pretty often one app have many commands. And option flags set additional parameters to that command. For example:
git log --source
rails s -p 3131
or pod install --help

I found really good example of argument parsing library for Go, called Cobra: https://github.com/spf13/cobra Which solves this task with ease. Is there a chance that you decide to add similar command parsing into Args?

Positional arguments example fails

I am trying this README example:

// Argument flags, Positional arguments, lists

#include <iostream>
#include <args.hxx>
int main(int argc, char **argv)
{
    args::ArgumentParser parser("This is a test program.", "This goes after the options.");
    args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
    args::ValueFlag<int> integer(parser, "integer", "The integer flag", {'i'});
    args::ValueFlagList<char> characters(parser, "characters", "The character flag", {'c'});
    args::Positional<std::string> foo(parser, "foo", "The foo position");
    args::PositionalList<double> numbers(parser, "numbers", "The numbers position list");
    try
    {
        parser.ParseCLI(argc, argv);
    }
    catch (args::Help)
    {
        std::cout << parser;
        return 0;
    }
    catch (args::ParseError e)
    {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return 1;
    }
    catch (args::ValidationError e)
    {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return 1;
    }
    if (integer) { std::cout << "i: " << args::get(integer) << std::endl; }
    if (characters) { for (const auto ch: args::get(characters)) { std::cout << "c: " << ch << std::endl; } }
    if (foo) { std::cout << "f: " << args::get(foo) << std::endl; }
    if (numbers) { for (const auto nm: args::get(numbers)) { std::cout << "n: " << nm << std::endl; } }
    return 0;
}

It prints:

# ./test -c x a b c d e
c: x
f: a
n: 0
n: 0
n: 0
n: 0

"n" is printed for double numbers and b c d e aren't numbers. Why does it print zeros for them?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.