GithubHelp home page GithubHelp logo

jarro2783 / cxxopts Goto Github PK

View Code? Open in Web Editor NEW
4.0K 58.0 576.0 1.01 MB

Lightweight C++ command line option parser

License: MIT License

CMake 2.09% C++ 97.79% Starlark 0.11%
c-plus-plus option-parser positional-arguments

cxxopts's People

Contributors

andersrosen avatar charlydelta avatar davidsanfal avatar dennisosrm avatar eyalroz avatar hillmich avatar j2bbayle avatar jarro2783 avatar jgonzalezdr avatar kjetand avatar ldeng-ustc avatar lemire avatar linus-sherrill avatar matthew-limbinar avatar mcourteaux avatar mxmlnkn avatar neheb avatar nickbp avatar nigels-com avatar nioshd avatar nocnokneo avatar nzsolt222 avatar objectx avatar ollien avatar pmed avatar ronxbulld avatar ryanleary avatar silvergasp avatar tesch1 avatar wichtounet 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cxxopts's Issues

wchar_t wstring

Hi, I'm testing the library with a win32 console unicode project is VS2015. Rather than icu as unicode, why not just use wchar_t and wstring?

Adding options with space causes program crash

Hello, I am about to ask a question, by raising this issue.

Summary

  • add_options() crashes when cla option definition string has a space in it, and want to know if this is intended.

Environment

  • VS2015 on Windows 7 x64
  • Debug(x86) is current project configuration

How to Reproduce This

cxxopts::Options options(argv[0], "Program for cxxopts");

options.add_options()
    ("d, debug", "Enables debug")
; // Note the space after "d,"

This causes crash at cxxopts.hpp:1018: cxxopts::invalid_option_format_error

const auto& short_match = result[2];

Why Do I Raise This Issue

  • I am new to C++ CLA library, and not sure if no whitespace between short/long option is allowed.
    • Is this a known convention when writing a CLA option?
  • Since I am also new to C++ regex handling, thus not sure if I can handle this issue such fast.

Positional parameters - overload ambiguity

Just went off the example and tried to use position parameters, like this:

options.parse_positional({"archive"});

However this fails with the errors:

error: call of overloaded ‘parse_positional(<brace-enclosed initializer list>)’ is ambiguous
   options.parse_positional({"archive"});
                                       ^
./cxxopts.hpp:1589:1: note: candidate: void cxxopts::Options::parse_positional(std::__cxx11::string)
 Options::parse_positional(std::string option)

./cxxopts.hpp:1596:1: note: candidate: void cxxopts::Options::parse_positional(std::vector<std::__cxx11::basic_string<char> >)
 Options::parse_positional(std::vector<std::string> options)

It seems if you only have one variable for the positional parameters to go into, you should not use a vector and use a string instead. I don't suppose there's any way to make the syntax uniform no matter how many parameters you specify? Maybe with an std::initializer_list overload too, or instead of them both?

Major changes to the API

In order to facilitate several requested enhancements I will be making major backwards incompatible changes to the API, and releasing it as version 2.0.

This issue is here to track the progress of the changes.

The biggest change will be the way parsing is handled. Rather than making a stateful change to the parser object, parsing will be stateless, and will return the result of the parse. This will allow for reusing the parser, and should also make it easier to iterate through the match results.

Allow using only short arguments

It would be great if it were possible to use only short arguments in some cases:

opts.add_options()("p", "The parameter p in the algorithm", cxxopts::value<bool>());

Example (alternative) syntax:

// empty string shows there's no long option
opts.add_options()("", "p", "The parameter p in the algorithm", cxxopts::value<bool>());

MACRO min/max under WINDOWS

C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1342): error C2589: '(': illegal token on right side of '::' 
C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1342): error C2062: type 'unknown-type' unexpected 
C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1342): error C2059: syntax error: ')' 
C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1346): error C2589: '(': illegal token on right side of '::' 
C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1346): error C2062: type 'unknown-type' unexpected 
C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1346): error C2059: syntax error: ')' 

the errors related with min and max in the library
cxxopts.hpp:

            longest = std::max(longest, stringLength(s));
            format.push_back(std::make_pair(s, String()));
        }

        longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));

the problem (Windows specifics) usually related with that there are macro definitions for min and max.
this (below) solves the problem :

image

I'll perform some tests and if this woks okay and will raise a PR with WINDOWS only ifdef

Positional arguments

It would be nice to improve a bit the handling of positional arguments to be
more unix-y. A practical example of what I'd have in mind:

cxxopts::Options options(argv[0], " - example command line options");
options.add_options()
  ("f,flag", "desc")
  ("input", "", cxxopts::value<string>(input), "INPUT")
  ("output", "", cxxopts::value<string>(output), "OUTPUT");
opts.parse(argc, argv, {"input", "output"});

Where:

  • the empty description suppresses the help for that option
  • the third argument to Options::parse is a list of positional arguments.
    Just a vector<string>, which is moved to m_positional (now a vector<string>
    as well).
  • short usage also iterates though m_positional to find argument names for
    consistent short help.
  • parse() finally consumes positional arguments in a simple loop.
    If a vector<> is encountered, it just eats all the remaining arguments.
  • parse_positional() is now just a compatibility stub that adds an element
    to m_positional, although I find it less clear than the above behavior.

This should result in the following help:

Usage:
  ./example [OPTION...] INPUT OUTPUT - example command line options

  -f, --flag desc

With no changes to the public interface (and minimal source changes as well).

Header-only version ?

Hi,

I was wondering if you considered making this library header only ? For a project with only one source file, it should not be hard to do and would make its usage much more practical.

I'd like to replace Boost PO with this library if it was header only.

Thanks

Required arguments

Hi,
Thanks for the software.
It would be great if there is an option to set some arguments as 'required', like in Boost::program_options:

std::string input;
boost::program_options::options_description options("Some arguments");
options.add_options()
        ("input", boost::program_options::value<std::string>(&input)->required(), "Path to input file")
;

Regards.

Problems when passing incorrect numbers

I write an application which I need to pass a debug level for logging.
As I tested my application I tried to catch all exceptions so I could provide good error messages for the user. When I tried to enter a string instead of an integer no exception got thrown, instead it parsed it to a valid integer. Also for the parser 0x0 is not a valid integer.
Furthermore when entering a decimal number without 0x it is still possible to use A-F in the number.

Test program:

#include "cxxopts.hpp"

int main(int argc, char *argv[]) {
    cxxopts::Options options("test", "");
    options.add_options()("d,debug", "enable debugging", cxxopts::value<int>());
    try {
        options.parse(argc, argv);

        if (options.count("debug")) {
            std::cout << options["debug"].as<int>() << std::endl;
        }

    } catch (cxxopts::argument_incorrect_type e) {
        std::cout << "The provided argument is of a wrong type" << std::endl;
    } catch (...) {
    }
    return 0;
}

Example outputs:
1.)

./testprogram -d 0x0
The provided argument is of a wrong type

2.)

./testprogram -d Ae
114

3.)

./testprogram -d test
1400

Expected outputs:

1.) 0
2.) The provided argument is of a wrong type
3.) The provided argument is of a wrong type

Remark to 2.) Because this is not valid in decimal notation
Remark to 3.) Because this is not a valid number

Parsing types other than standard ones

README.md says "Any type can be given as long as it can be parsed, with operator>>." but it does not work for types such as enum classes. In fact, i don't see any call to operator>> in the source.
Defining void parse_value(const std::string& text, MYTYPE & value) works perfectly, and throwing a cxxopts::argument_incorrect_type in parse_value for a wrong value also works perfectly.
Is defining parse_value the right way to do it (so i suppose the README needs an update, because it is a interesting feature), or is it just an undocumented feature that could be removed in future releases?

error parsing options: Option ‘t’ does not exist

I get a strange strings when running this code without a valid option:

 options.add_options("")
	("a,aaaa", "aaaa type", cxxopts::value<std::string>()->default_value("bbbb"), "bbbb or cccc")
			("h,help", "Print help");
	options.parse(argc, argv);
	if (options.count("help"))
	{
		std::cout << options.help({ "", "Group" }) << std::endl;
		exit(0);
	}


Build is on Windows with MSVC community 15

Can you add default values to options (so that they are optional)?

I would like to have an option, that takes a value. But if the option is not given, a default value should be used. Is this possible here?

I know I can check explicitly whether the option was entered via "count". But I was wondering if there was an API dedicated to this?

Adding help text after `[OPTION...]` (or hiding help text intro)

My code (which I am moving to cxxopts) currently displays the usage like this, when --help is passed:

Usage: gamecomp -t <type> < infile > outfile

However cxxopts displays it like this:

Usage:
  gamecomp [OPTION...]

I can't see a way to write any text after [OPTION...], so that I can put < infile > outfile onto the end of that line.

I also can't see a way to hide the intro text and usage line entirely so I can write it myself with my own code, and have cxxopts only display the bare argument list.

Is one of these things possible? Given the choice, being allowed to omit the parameters to cxxopts::Options() to cause it to skip displaying the intro text would be the most flexible I think. I tried passing in two blank strings but I still get the Usage: line.

New release ?

@jarro2783 we use your project to manage the options in a Jupyter cell with https://github.com/QuantStack/xeus-cling.

We would like to package your application in order to install cxxopts with conda and to manage the dependencies of our xeus-cling project. But to be able to do that, we need a new release with the fix #61.

@SylvainCorlay will do the packaging for conda.

Could you do a new release ?

Implicit / Default bool values

Right now, bool parsing is left as a TODO that just always says true.

Given:
("r,recursive", "Do the thing recursively", cxxopts::value<bool>()->default_value("")->implicit_value("true"))
I expect the following:

  • If the option is missing entirely, it is false.
  • If the option given as -r or --recursive without a value, it's interpreted as true.
  • If a value is given, it's parsed from common "truthy" strings.

There is no changelog or versioning

There is no changelog recording changes across versions. There is also nothing indicating the version of the library in the code. Currently the only version indicator is a git tag.

nested option groups

does the lib supports nested option groups like boost::program_options? I mean an ability to create a few independent groups of options and use one of them depends of group selection

Numbers aren't supported as options

Currently, using a number as an option will throw an invalid_option_format_error exception. In order to allow parsing options such as

./test -v -6

can numbers be added to the option_specifier regex?

Exclusive groups

Sometimes we only want to allow only one of a few options at one time.

    opts.add_options()
            ("file", "Read data from file", cxxopts::value<std::string>())
            ("generate", "Generate a random network")
            ("anothergenerate", "Generate a random network with a different algorithm");

It would be really useful to mark a group as exclusive, so that cxxopts would raise an error when two of the opts are used.

Multiple definitions

I would like to use cxxopts in several source files but it seems that it is not possible. I have compilation errors mentioning that there exists multiple definitions.

To have an example, I just take the one given in the source code and I have added sum.hpp and sum.cpp with the following content

#ifndef SUM_HPP
#define SUM_HPP

#include "cxxopts.hpp"
double sum(double a, double b);
#endif  
#include "cxxopts.hpp"
#include "sum.hpp"

double sum(double a, double b)
{
    return a + b;
}

And then I have added

#include "sum.hpp"

and I have added the source file sum.cpp in the CMakeLists.txt. When you compile this example, you will have multiple definitions error.

Positional arguments should be required (?)

If some positional arguments are not set, then options.parse(argc, argv) should print help message and exit.

(just a suggestion -- this is the default behaviour of python argparse)

default value for double options

options.add_options()
     ("myoption", "myoption description", cxxopts::value<double>()->default_value(0.1));

fails with:
/home/xs/proj/daedalean/exp/user/xs/vo_eval/src/cpp/main.cpp:25: error: reference to type 'const std::string' (aka 'const basic_string<char>') could not bind to an rvalue of type 'double' , cxxopts::value<double>()->default_value(0.1));

it looks like default values are only supported for strings at the moment. Might be a good idea to fix the documentation before the code fix is ready.

Positional parameters overwrite named parameters

If a named parameter is used in positional parameters, and that named parameter is given first before some positional parameters, the positional parameter overrides the value of the named parameter already given.

The correct behaviour would be that since the named parameter has already been given, the parameter is skipped when consuming positional arguments.

implicit value is used when arg is 'empty string'

I have an option with implicit argument (let's say -w [<arg>(=ABC)]). When I invoke my app with arg = 'empty string' (i.e. <mybinary> -w "") -- option takes value of 'ABC'.

I am pretty sure shell passes such cmdline params as empty strings into main(). Looks like a bug.

SUGGESTION: Use lambdas for more power

I'd made a similar class for my KGB2 project. I think you could look over the implementation and get a good idea for using lambdas to solve problems. In my program, the option handling had to be able to identify options as given by the programmer, so it would identify long and short options with user-given lambdas.
Here's the code (in case something happens to my project):
opthandling.hpp:

#ifndef KGB_OPT_HANDLING
#define KGB_OPT_HANDLING

#include <functional>
#include <string>
#include <vector>

struct option {
	option(std::string so, std::string lo, std::string ds, std::function<void (const std::string&)> fd);
	option(std::string so, std::string lo, std::string ds, std::function<void (const std::string&)> fd, std::function<bool (const std::string&)> sis);
	option(std::string so, std::string lo, std::string ds, std::function<void (const std::string&)> fd, std::function<bool (const std::string&)> sis, std::function<bool (const std::string&)> lis);
	option(std::string so, std::string ds, std::function<void (const std::string&)> fd);
	option(std::string so, std::string ds, std::function<void (const std::string&)> fd, std::function<bool (const std::string&)> sis);
	option(std::string so, std::string ds, std::function<void (const std::string&)> fd, std::function<bool (const std::string&)> sis, std::function<bool (const std::string&)> lis);
	std::string sopt;
	std::string lopt;
	std::string descrip;
	bool has_long_opt = true;
	bool has_short_opt = true;
	std::function<void (const std::string&)> found;
	std::function<bool (const std::string&)> s_is;
	std::function<bool (const std::string&)> l_is;
};

void opt_handler(int argc, const char* argv[], std::string command, std::string invocation, std::string short_description,
	std::vector<option> gopts, std::function<void (const std::string&)> unknown_opt_handler);

#endif

Here's opthandling.cpp:

#include "opthandling.hpp"

#include "strio.hpp"
#include "config.hpp"
#include <cstring>
#include <iomanip>
#include <iostream>

using namespace std;

option::option(string so, string lo, string ds, function<void (const string&)> fd):
	sopt(so), lopt(lo), descrip(ds), has_long_opt(true), found(fd) {
	s_is = [&] (string obj) -> bool {return strcmp(sopt.c_str(), obj.c_str())==0;};
	l_is = [&] (string obj) -> bool {return strcmp(lopt.c_str(), obj.c_str())==0;};
}
option::option(string so, string lo, string ds, function<void (const string&)> fd, function<bool (const string&)> sis): sopt(so), lopt(lo), descrip(ds), has_long_opt(true), found(fd), s_is(sis) {}
option::option(string so, string lo, string ds, function<void (const string&)> fd, function<bool (const string&)> sis, function<bool (const string&)> lis):
	sopt(so), lopt(lo), descrip(ds), has_long_opt(true), found(fd), s_is(sis), l_is(lis) {}
option::option(string so, string ds, function<void (const string&)> fd): sopt(so), descrip(ds), has_long_opt(false), found(fd) {
	s_is = [&] (string obj) -> bool {return strcmp(sopt.c_str(), obj.c_str())==0;};
	l_is = 0;
}
option::option(string so, string ds, function<void (const string&)> fd, function<bool (const string&)> sis): sopt(so), descrip(ds), has_long_opt(false), found(fd), s_is(sis) {}
option::option(string so, string ds, function<void (const string&)> fd, function<bool (const string&)> sis, function<bool (const string&)> lis):
	sopt(so), descrip(ds), has_long_opt(false), found(fd), s_is(sis), l_is(lis) {}

void opt_handler(int argc, const char* argv[], string command, string invocation, string short_description,
	vector<option> gopts, function<void (const string&)> unknown_opt_handler) {
	bool eoop = false; // End Of Option Processing
	int opt_num = gopts.size();
	if (argc == 1 || strcmp(argv[1],"-h")==0 || strcmp(argv[1],"--help")==0) {
		printf(PACKAGE_NAME ": %s Help\n"
			"  The %s command (invoked with \"kgb %s\") %s.\n"
			"USAGE:\n"
			"  kgb %s\n" , command.c_str(), command.c_str(), invocation.substr(0,1).c_str(), short_description.c_str(), invocation.c_str());
		if (opt_num == 0) exit(0);
		printf("OPTIONS:\n");
		int sos = 0, los = 0;
		for (int i = 0; i < opt_num; ++i) {
			if (sos<int(gopts[i].sopt.size())) sos = gopts[i].sopt.size();
			if (los<int(gopts[i].lopt.size())) los = gopts[i].lopt.size();
		}
		sos++; los++;
		for (int i = 0; i < opt_num; ++i)
			if (gopts[i].has_long_opt&&gopts[i].has_short_opt)
				printf("  -%-*s| --%-*s| %s\n", sos, gopts[i].sopt.c_str(), los, gopts[i].lopt.c_str(), gopts[i].descrip.c_str());
			else if (!gopts[i].has_long_opt && gopts[i].has_short_opt)
				printf("  -%-*s| %-*s| %s\n", sos, gopts[i].sopt.c_str(), los+2, "-", gopts[i].descrip.c_str());
			else if (gopts[i].has_long_opt&&!gopts[i].has_short_opt)
				printf("  -%-*s| --%-*s| %s\n", sos, "-", los, gopts[i].lopt.c_str(), gopts[i].descrip.c_str());
		exit(0);
	}
	argv++; argc--;
	for (int i=0; i<argc; ++i) {
		if (strlen(argv[i])>=2&&strcmp(string(1,argv[i][0]).c_str(),"-")==0&&!eoop) {
			// Long options
			if (strlen(argv[i])>2&&strcmp(string(1,argv[i][1]).c_str(),"-")==0) {
				string lopt = string(argv[i]).substr(2,strlen(argv[i]));
				bool fnd = false;
				for (int k = 0; k < opt_num; ++k) if (gopts[k].l_is(lopt.c_str())) {
					gopts[k].found(lopt);
					fnd = true;
					break;
				}
				if (!fnd) prerr("Unknown long option \"%s\"!", argv[i], 0);
				continue;
			}
			if (strcmp(argv[i],"--")==0) {eoop = true; continue; }
			// Short options
			bool fnd = false; // Check if option not found
			for (int j=1; j<int(strlen(argv[i])); ++j) {
				for (int k=0; k < opt_num; ++k)
					if (gopts[k].s_is(string(1,argv[i][j]))) {
						gopts[k].found(string(1,argv[i][j]));
						fnd = true;
						break;
					}
				if (fnd) fnd = false;
				else prerr("Unknown short option \"-%c\"!", argv[i][j], 0);
			}
		} else unknown_opt_handler(string(argv[i]));
	}
}

It automatically generates a description based on given options.
Here's an example for an extract command:

opt_handler(argc, argv, "Extract", "x [<options>] <archive>", "extracts files from an archive", vector<option>({
		option("v",     "verbose", "Activates verbose flag",      [&] (string in) {opt.vbs=true;}),
		option("q",     "quiet",   "Activates quiet output",      [&] (string in) {opt.quiet=true;opt.vbs=false;}),
		option("f",     "force",   "Activates overwrite flag",    [&] (string in) {opt.owa=true;opt.own=false;}),
		option("n",     "no-act",  "Activates no-overwrite flag", [&] (string in) {opt.own=true;opt.owa=false;}),
                option("<mem>",            "Compression level (0-9)",       [&] (string in) {opt.mem=in[0]-'0';}, [&] (string so) -> bool {return isdigit(so[0]);})
	}), [&] (string arg) {
               // Normal arg recogniser
        }
});

My output for no more aguments (so help message) would be:
$ ./kgb x

KGB Archiver: Extract Help
  The Extract command (invoked with "kgb x") extracts files from an archive.
USAGE:
  kgb x [<options>] <archive>
OPTIONS:
  -v | --verbose | Activates verbose flag
  -q | --quiet   | Activates quiet output
  -f | --force   | Activates overwrite flag
  -n | --no-act  | Activates no-overwrite flag

It's currently a work-in-progress for only-long-option processing

Is iterating over the options possible?

Is it possible to iterate over the non-positional options?

My program works by performing actions, in order, as they are specified on the command line. So for example I might do something like this:

./example --add newfile.txt --delete existing.txt --rename newfile.txt=existing.txt

If those operations happen in a different order then the program won't work, so I need a way to find out what the first option and its parameter are (and action it), then look at the second option and its parameter, and so on.

boost::program_options offers a std::vector of the options, in the order given on the command line - is there an equivalent here, or some other way to achieve this functionality?

Optional and mandatory options

I think it would be nice to have optional and mandatory options
that way no validation is needed to be done by the user

Count duplicate option occurences

Hello,

I was wondering if there is a way to specify duplicate flags and have cxxopts count the occurrences. For instance, I would like to have a verbose options with increasing levels of verbosity so that I can give: -v, -vv, -vvv, -v -v -v, ect.. and calling options.count("verbose") should return 1, 2, 3, and 3 respectively.

This behavior is similar to the argument parser in python (see the 'count' action): https://docs.python.org/3/library/argparse.html#action

Is there any way to disallow arguments to be used like -abc?

I have defined the following options.

        options.add_options()
            ("c,clean"  , "Clean folder")
            ("p,project", "Path to project file", cxxopts::value<std::string>())
            ("h,help"   , "Print help");

And it can be used with program -c or program --clean which is perfect.

Is there anyway to disable it from working like program -chp ?
This basically triggers all three options, like I would've used program -c -h -p something.

options.help({}) doesn't show positional arguments sometimes

Code sample:

int main(int argc, char *argv[]) {
    try {
        cxxopts::Options options(argv[0], "Sample");
        options.positional_help("<Extra args>");
        
        options.add_options()
        ("s,set", "Set whatever.", cxxopts::value<std::vector<std::string>>())
        ("h,help", "Print help and exit.")
        ;
       
        options.parse(argc, argv);
        options.parse_positional({"file", "remove-label", "set-label"});
       
        // help
        if (options.count("help")) {
        cout << options.help({""}) << std::endl;
        exit(0);
        }
    } catch (const cxxopts::OptionException& e) {
        cout << "error parsing options: " << e.what() << std::endl;
        exit(-1);
        }
    return 0;
}

Expected: Show the "set" option in the help.
Actual: Show only "help" option.

Positional args are handled incorrectly when -- is present

Test program:

#include "cxxopts.hpp"
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    for (int i = 0; i < argc; ++i)
        cout << i << " " << argv[i] << "\n";

    cxxopts::Options options("posargmaster", "shows incorrect handling");
    options.add_options()
        ("dummy", "oh no", cxxopts::value<string>())
        ;

    options.parse(argc, argv);

    for (int i = 0; i < argc; ++i)
        cout << i << " " << argv[i] << "\n";

    return 0;
}

Example invocations and output:

$ ./a.out a b
0 ./a.out
1 a
2 b
0 ./a.out
1 a
2 b

$ ./a.out -- a b
0 ./a.out
1 --
2 a
3 b
0 ./a.out

It could be i am missing something, but this seems strange to me. Is this the intended behavior? If so, how should I access the positional arguments when -- is used?

Provide "positional parameters" text

The wording "positional parameters" is quite technical, and I would prefer to specify what this should be, when I set up the options. Currently, I am doing this manually using a string replace of the help text before presenting it to my user. For example, in my application, I actually present this text:
[SCHEMA ...]

I was confused about this, since the "positional" option in the example.cpp did provide text for this, but I looked at the code, and it seems to just be hardwired to "positional parameters".

Thanks for considering this!

GCC warnings with -Wshadow

After update gcc starts showing warnings during compilation (-Wshadow):

/home/ksergey/dev/bitfinex_feed_handler/deps/cxxopts/include/cxxopts.hpp:1028:3: warning: declaration of ‘l’ shadows a previous local [-Wshadow]
   )
   ^
/home/ksergey/dev/bitfinex_feed_handler/deps/cxxopts/include/cxxopts.hpp:1014:15: note: shadowed declaration is here
   const auto& l = result[3];
               ^
/home/ksergey/dev/bitfinex_feed_handler/deps/cxxopts/include/cxxopts.hpp:1028:3: warning: declaration of ‘s’ shadows a previous local [-Wshadow]
   )
   ^
/home/ksergey/dev/bitfinex_feed_handler/deps/cxxopts/include/cxxopts.hpp:1013:15: note: shadowed declaration is here
   const auto& s = result[2];
               ^

Could you please fix that?

Add handling of -- to end options

Although prog -a -b - works to specify - as the first positional argument (or input in the example, being able to end the options explicitly via -- has its place, e.g.:

prog -a -b -- -silly-filename

See also Guideline 10 of Posix Utility Conventions, 12.1 Utility Argument Syntax:

Guideline 10:
The first -- argument that is not an option-argument should be accepted as a delimiter indicating the end of options. Any following arguments should be treated as operands, even if they begin with the '-' character.

Hide options from help.

I don't see a way of hiding an option from appearing when help() is called. I would like to use this for my positional arguments. Is it difficult to add?

Garbled font when giving unknown option

Hi,

I'm running the example app from this repo.
When I give it an unkown option, for example run example.exe -e, I get all garbled output:

error parsing options: Option ├óÔé¼╦£e├óÔé¼Ôäó does not exist
Press any key to continue . . .

This is on VS 2017 Preview (15.3.0 Preview 7.1), x64. Happens in Debug and Release build. I didn't change any of the default options of the example app, so e.g. CXXOPTS_USE_UNICODE is not defined.

Running the tests:

===============================================================================
All tests passed (53 assertions in 13 test cases)

Press any key to continue . . .

Multiple definitions of `cxxopts::values::integer_pattern`

Creating a global value does makes one version of it per compilation unit, which causes problems at link time when cxxopts is used in more than one compilation units.

Instead of doing

namespace
{
  std::basic_regex<char> integer_pattern
    ("(-)?(0x)?([1-9a-zA-Z][0-9a-zA-Z]*)|(0)");
}

you probably should have

inline const std::basic_regex<char>& integer_pattern()
{
    static const std::basic_regex<char> pattern = "(-)?(0x)?([1-9a-zA-Z][0-9a-zA-Z]*)|(0)";
    return pattern;
}

i.e. make a singleton.

vector<string> for positional arguments with spaces not working

With the command line example as an example,
$ ./example "in put" "out put" "spaces not working"
will error out: "error parsing options: Argument ‘spaces not working’ failed to parse"
Without "spaces not working", the example program will parse without a problem

Help message for positional arguments

help message is somewhat strange for positional arguments:
(taken from your example.cpp)

program_name [OPTIONS]

      --positional arg          Positional arguments: these are the arguments
                                        that are entered without an option

Is double dash intended?
Should it be smth like?:

program_name positional [OPTIONS]

 positional                       Positional arguments: these are the arguments
                                        that are entered without an option

thanks!

MSVC warnings

There are several warnings when compiling with MSVC (toolset v140 = VS2015):

  1. ..\cxxopts.hpp(528): warning C4146: unary minus operator applied to unsigned type, result still unsigned

The context:

      if (negative)
      {
        if (!is_signed)
        {
          throw argument_incorrect_type(text);
        }
        value = -result; // <<< warning C4146
      }
      else
      {
        value = result;
      }
  1. ..\cxxopts.hpp(442): warning C4018: '>': signed/unsigned mismatch
    The context:
      template <typename T>
      struct SignedCheck<T, true>
      {
        template <typename U>
        void
        operator()(bool negative, U u, const std::string& text)
        {
          if (negative)
          {
            if (u > U(-std::numeric_limits<T>::min())) // <<< warning C4018
            {
              throw argument_incorrect_type(text);
            }
          }
          else
          {
            if (u > std::numeric_limits<T>::max())
            {
              throw argument_incorrect_type(text);
            }
          }
        }
      };

Using std::vector<std::string> instead of argc, argv

Before you reply to my issue #65, I have a question.

In our program, we need to parse a std::string instead of using argc, argv. The options are in this string. So to be able to use cxxopts I do a hack of the Options class and add two functions

void parse(std::vector<std::string>& argv);
void checked_parse_arg 
        (
        std::vector<std::string>& argv,
        int& current,
        std::shared_ptr<cxxopts::OptionDetails> value,
        const std::string& name
        );

The use case is

std::istringstream iss(line);
std::vector<std::string> results((std::istream_iterator<std::string>(iss)),
                                                  std::istream_iterator<std::string>());
auto options = get_options();
options.parse(results);

where line is the string to parse and we split this line with the space delimiter and set the result in a vector of string.

Did you already think about this use case ? What is the best thing to do ? Add a PR with this work ?

Reparse not possible without a reset method or alike

I discovered that after one parse() call, the state of the parsed options is kept if doing a new parse (with different argc/argv). Parse would need to reset the state before starting, either by implicit or that the user has to call to a reset method or such.

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.