getopt fails to detect missing argument for option - c++

I have a program which takes various command line arguments. For the sake of simplification, we will say it takes 3 flags, -a, -b, and -c, and use the following code to parse my arguments:
int c;
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
switch (c)
{
case 'a':
cout << optarg << endl;
break;
case 'b':
cout << optarg << endl;
break;
case ':':
cerr << "Missing option." << endl;
exit(1);
break;
}
}
note: a, and b take parameters after the flag.
But I run into an issue if I invoke my program say with
./myprog -a -b parameterForB
where I forgot parameterForA, the parameterForA (represented by optarg) is returned as -b and parameterForB is considered an option with no parameter and optind is set to the index of parameterForB in argv.
The desired behavior in this situation would be that ':' is returned after no argument is found for -a, and Missing option. is printed to standard error. However, that only occurs in the event that -a is the last parameter passed into the program.
I guess the question is: is there a way to make getopt() assume that no options will begin with -?

See the POSIX standard definition for getopt. It says that
If it [getopt] detects a missing
option-argument, it shall return the
colon character ( ':' ) if the first
character of optstring was a colon, or
a question-mark character ( '?' )
otherwise.
As for that detection,
If the option was the last character in the string pointed to by
an element of argv, then optarg shall
contain the next element of argv, and
optind shall be incremented by 2. If
the resulting value of optind is
greater than argc, this indicates a
missing option-argument, and getopt()
shall return an error indication.
Otherwise, optarg shall point to the string following the option
character in that element of argv, and
optind shall be incremented by 1.
It looks like getopt is defined not to do what you want, so you have to implement the check yourself. Fortunately, you can do that by inspecting *optarg and changing optind yourself.
int c, prev_ind;
while(prev_ind = optind, (c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if ( optind == prev_ind + 2 && *optarg == '-' ) {
c = ':';
-- optind;
}
switch ( …

If you are working in C++, boost::program_option is my recommendation to parse command line argument:
Boost::program_options library

Full disclosure: I'm no expert on this matter.
Would this example from gnu.org be of use? It seems to handle the '?' character in cases where an expected argument was not supplied:
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
update: Perhaps the following would work as a fix?
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if (optarg[0] == '-')
{
c = ':';
}
switch (c)
{
...
}
}

As an alternative for Boost-free projects, I have a simple header-only C++ wrapper for getopt (under The BSD 3-Clause License): https://github.com/songgao/flags.hh
Taken from example.cc in the repo:
#include "Flags.hh"
#include <cstdint>
#include <iostream>
int main(int argc, char ** argv) {
uint64_t var1;
uint32_t var2;
int32_t var3;
std::string str;
bool b, help;
Flags flags;
flags.Var(var1, 'a', "var1", uint64_t(64), "This is var1!");
flags.Var(var2, 'b', "var2", uint32_t(32), "var2 haahahahaha...");
flags.Var(var3, 'c', "var3", int32_t(42), "var3 is signed!", "Group 1");
flags.Var(str, 's', "str", std::string("Hello!"), "This is a string, and the description is too long to fit in one line and has to be wrapped blah blah blah blah...", "Group 1");
flags.Bool(b, 'd', "bool", "this is a bool variable", "Group 2");
flags.Bool(help, 'h', "help", "show this help and exit", "Group 3");
if (!flags.Parse(argc, argv)) {
flags.PrintHelp(argv[0]);
return 1;
} else if (help) {
flags.PrintHelp(argv[0]);
return 0;
}
std::cout << "var1: " << var1 << std::endl;
std::cout << "var2: " << var2 << std::endl;
std::cout << "var3: " << var3 << std::endl;
std::cout << "str: " << str << std::endl;
std::cout << "b: " << (b ? "set" : "unset") << std::endl;
return 0;
}

There are quite a few different versions of getopt around, so even if you can get it to work for one version, there will probably be at least five others for which your workaround will break. Unless you have an overwhelming reason to use getopt, I'd consider something else, such as Boost.Program_options.

Related

How to assign a values to "cin>>variable" in command line [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Closed 2 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What is the best way of parsing command-line arguments in C++ if the program is specified to be run like this:
prog [-abc] [input [output]]
Is there some way of doing this built into the standard library, or do I need to write my own code?
Related:
Parsing command line arguments in a unicode C++ application
The suggestions for boost::program_options and GNU getopt are good ones.
However, for simple command line options I tend to use std::find
For example, to read the name of a file after a -f command line argument. You can also just detect if a single-word option has been passed in like -h for help.
#include <algorithm>
char* getCmdOption(char ** begin, char ** end, const std::string & option)
{
char ** itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}
bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
return std::find(begin, end, option) != end;
}
int main(int argc, char * argv[])
{
if(cmdOptionExists(argv, argv+argc, "-h"))
{
// Do stuff
}
char * filename = getCmdOption(argv, argv + argc, "-f");
if (filename)
{
// Do interesting things
// ...
}
return 0;
}
On thing to look out for with this approach you must use std::strings as the value for std::find otherwise the equality check is performed on the pointer values.
I hope it is okay to edit this response instead adding a new one, as this is based on the original answer. I re-wrote the functions slightly and encapsulated them in a class, so here is the code. I thought it might be practical to use it that way as well:
class InputParser{
public:
InputParser (int &argc, char **argv){
for (int i=1; i < argc; ++i)
this->tokens.push_back(std::string(argv[i]));
}
/// #author iain
const std::string& getCmdOption(const std::string &option) const{
std::vector<std::string>::const_iterator itr;
itr = std::find(this->tokens.begin(), this->tokens.end(), option);
if (itr != this->tokens.end() && ++itr != this->tokens.end()){
return *itr;
}
static const std::string empty_string("");
return empty_string;
}
/// #author iain
bool cmdOptionExists(const std::string &option) const{
return std::find(this->tokens.begin(), this->tokens.end(), option)
!= this->tokens.end();
}
private:
std::vector <std::string> tokens;
};
int main(int argc, char **argv){
InputParser input(argc, argv);
if(input.cmdOptionExists("-h")){
// Do stuff
}
const std::string &filename = input.getCmdOption("-f");
if (!filename.empty()){
// Do interesting things ...
}
return 0;
}
Boost.Program_options should do the trick
I can suggest Templatized C++ Command Line Parser Library (some forks on GitHub are available), the API is very straightforward and (cited from the site):
the library is implemented entirely in header files making it easy to
use and distribute with other software. It is licensed under the MIT
License for worry free distribution.
This is an example from the manual, colored here for simplicity:
#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>
int main(int argc, char** argv)
{
// Wrap everything in a try block. Do this every time,
// because exceptions will be thrown for problems.
try {
// Define the command line object, and insert a message
// that describes the program. The "Command description message"
// is printed last in the help text. The second argument is the
// delimiter (usually space) and the last one is the version number.
// The CmdLine object parses the argv array based on the Arg objects
// that it contains.
TCLAP::CmdLine cmd("Command description message", ' ', "0.9");
// Define a value argument and add it to the command line.
// A value arg defines a flag and a type of value that it expects,
// such as "-n Bishop".
TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");
// Add the argument nameArg to the CmdLine object. The CmdLine object
// uses this Arg to parse the command line.
cmd.add( nameArg );
// Define a switch and add it to the command line.
// A switch arg is a boolean argument and only defines a flag that
// indicates true or false. In this example the SwitchArg adds itself
// to the CmdLine object as part of the constructor. This eliminates
// the need to call the cmd.add() method. All args have support in
// their constructors to add themselves directly to the CmdLine object.
// It doesn't matter which idiom you choose, they accomplish the same thing.
TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);
// Parse the argv array.
cmd.parse( argc, argv );
// Get the value parsed by each arg.
std::string name = nameArg.getValue();
bool reverseName = reverseSwitch.getValue();
// Do what you intend.
if ( reverseName )
{
std::reverse(name.begin(),name.end());
std::cout << "My name (spelled backwards) is: " << name << std::endl;
}
else
std::cout << "My name is: " << name << std::endl;
} catch (TCLAP::ArgException &e) // catch any exceptions
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}
Boost.Program_options
You can use GNU GetOpt (LGPL) or one of the various C++ ports, such as getoptpp (GPL).
A simple example using GetOpt of what you want (prog [-ab] input) is the following:
// C Libraries:
#include <string>
#include <iostream>
#include <unistd.h>
// Namespaces:
using namespace std;
int main(int argc, char** argv) {
int opt;
string input = "";
bool flagA = false;
bool flagB = false;
// Retrieve the (non-option) argument:
if ( (argc <= 1) || (argv[argc-1] == NULL) || (argv[argc-1][0] == '-') ) { // there is NO input...
cerr << "No argument provided!" << endl;
//return 1;
}
else { // there is an input...
input = argv[argc-1];
}
// Debug:
cout << "input = " << input << endl;
// Shut GetOpt error messages down (return '?'):
opterr = 0;
// Retrieve the options:
while ( (opt = getopt(argc, argv, "ab")) != -1 ) { // for each option...
switch ( opt ) {
case 'a':
flagA = true;
break;
case 'b':
flagB = true;
break;
case '?': // unknown option...
cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
break;
}
}
// Debug:
cout << "flagA = " << flagA << endl;
cout << "flagB = " << flagB << endl;
return 0;
}
GNU GetOpt.
A simple example using GetOpt:
// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>
// Namespaces:
using namespace std;
int main(int argc, char** argv) {
int opt;
bool flagA = false;
bool flagB = false;
// Shut GetOpt error messages down (return '?'):
opterr = 0;
// Retrieve the options:
while ( (opt = getopt(argc, argv, "ab")) != -1 ) { // for each option...
switch ( opt ) {
case 'a':
flagA = true;
break;
case 'b':
flagB = true;
break;
case '?': // unknown option...
cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
break;
}
}
// Debug:
cout << "flagA = " << flagA << endl;
cout << "flagB = " << flagB << endl;
return 0;
}
You can also use optarg if you have options that accept arguments.
Yet another alternative is The Lean Mean C++ Option Parser:
http://optionparser.sourceforge.net
It is a header-only library (just a single header file, in fact) and unlike all the other suggestions it is
also freestanding, i.e. it has no dependencies whatsoever. In particular there's no dependency on the STL. It does not even use exceptions or anything else that requires library support. This means it can be linked with plain C or other languages without introducing "foreign" libraries.
Like boost::program_options its API offers convenient direct access to options,
i.e. you can write code like this
if (options[HELP]) ... ;
and
int verbosity = options[VERBOSE].count();
Unlike boost::program_options however this is simply using an array indexed with a (user-provided) enum. This offers the convenience of an associative container without the weight.
It's well documented and has a company-friendly license (MIT).
TLMC++OP includes a nice formatter for usage messages that can do
line-wrapping and column alignment which is useful if you're localizing your program, because it ensures that the output will look good even in languages that have longer messages. It also saves you the nuisance of manually formatting your usage for 80 columns.
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i],"-i")==0) {
filename = argv[i+1];
printf("filename: %s",filename);
} else if (strcmp(argv[i],"-c")==0) {
convergence = atoi(argv[i + 1]);
printf("\nconvergence: %d",convergence);
} else if (strcmp(argv[i],"-a")==0) {
accuracy = atoi(argv[i + 1]);
printf("\naccuracy:%d",accuracy);
} else if (strcmp(argv[i],"-t")==0) {
targetBitRate = atof(argv[i + 1]);
printf("\ntargetBitRate:%f",targetBitRate);
} else if (strcmp(argv[i],"-f")==0) {
frameRate = atoi(argv[i + 1]);
printf("\nframeRate:%d",frameRate);
}
}
TCLAP is a really nice lightweight design and easy to use:
http://tclap.sourceforge.net/
You probably want to use an external library for that. There are many to chose from.
Boost has a very feature-rich (as usual) library Boost Program Options.
My personal favorite for the last few years has been TCLAP -- purely templated, hence no library or linking, automated '--help' generation and other goodies. See the simplest example from the docs.
I find it easier to use ezOptionParser. It's also a single header file, does not depend on anything but STL, works for Windows and Linux (very likely other platforms too), has no learning curve thanks to the examples, has features other libraries don't (like file import/export with comments, arbitrary option names with delimiters, auto usage formatting, etc), and is LGPL licensed.
If you just want to process command line options yourself, the easiest way is to put:
vector<string> args(argv + 1, argv + argc);
at the top of your main(). This copies all command-line arguments into a vector of std::strings. Then you can use == to compare strings easily, instead of endless strcmp() calls. For example:
int main(int argc, char **argv) {
vector<string> args(argv + 1, argv + argc);
string infname, outfname;
// Loop over command-line args
// (Actually I usually use an ordinary integer loop variable and compare
// args[i] instead of *i -- don't tell anyone! ;)
for (auto i = args.begin(); i != args.end(); ++i) {
if (*i == "-h" || *i == "--help") {
cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
return 0;
} else if (*i == "-i") {
infname = *++i;
} else if (*i == "-o") {
outfname = *++i;
}
}
}
[EDIT: I realised I was copying argv[0], the name of the program, into args -- fixed.]
And there's a Google library available.
Really, command-line parsing is "solved." Just pick one.
With C++, the answer is usually in Boost...
Boost.Program Options
Try Boost::Program Options. It allows you to read and parse command lines as well as config files.
I think that GNU GetOpt is not too immediate to use.
Qt and Boost could be a solution, but you need to download and compile a lot of code.
So I implemented a parser by myself that produces a std::map<std::string, std::string> of parameters.
For example, calling:
./myProgram -v -p 1234
map will be:
["-v"][""]
["-p"]["1234"]
Usage is:
int main(int argc, char *argv[]) {
MainOptions mo(argc, argv);
MainOptions::Option* opt = mo.getParamFromKey("-p");
const string type = opt ? (*opt).second : "";
cout << type << endl; /* Prints 1234 */
/* Your check code */
}
MainOptions.h
#ifndef MAINOPTIONS_H_
#define MAINOPTIONS_H_
#include <map>
#include <string>
class MainOptions {
public:
typedef std::pair<std::string, std::string> Option;
MainOptions(int argc, char *argv[]);
virtual ~MainOptions();
std::string getAppName() const;
bool hasKey(const std::string&) const;
Option* getParamFromKey(const std::string&) const;
void printOptions() const;
private:
typedef std::map<std::string, std::string> Options;
void parse();
const char* const *begin() const;
const char* const *end() const;
const char* const *last() const;
Options options_;
int argc_;
char** argv_;
std::string appName_;
};
MainOptions.cpp
#include "MainOptions.h"
#include <iostream>
using namespace std;
MainOptions::MainOptions(int argc, char* argv[]) :
argc_(argc),
argv_(argv) {
appName_ = argv_[0];
this->parse();
}
MainOptions::~MainOptions() {
}
std::string MainOptions::getAppName() const {
return appName_;
}
void MainOptions::parse() {
typedef pair<string, string> Option;
Option* option = new pair<string, string>();
for (const char* const * i = this->begin() + 1; i != this->end(); i++) {
const string p = *i;
if (option->first == "" && p[0] == '-') {
option->first = p;
if (i == this->last()) {
options_.insert(Option(option->first, option->second));
}
continue;
} else if (option->first != "" && p[0] == '-') {
option->second = "null"; /* or leave empty? */
options_.insert(Option(option->first, option->second));
option->first = p;
option->second = "";
if (i == this->last()) {
options_.insert(Option(option->first, option->second));
}
continue;
} else if (option->first != "") {
option->second = p;
options_.insert(Option(option->first, option->second));
option->first = "";
option->second = "";
continue;
}
}
}
void MainOptions::printOptions() const {
std::map<std::string, std::string>::const_iterator m = options_.begin();
int i = 0;
if (options_.empty()) {
cout << "No parameters\n";
}
for (; m != options_.end(); m++, ++i) {
cout << "Parameter [" << i << "] [" << (*m).first << " " << (*m).second
<< "]\n";
}
}
const char* const *MainOptions::begin() const {
return argv_;
}
const char* const *MainOptions::end() const {
return argv_ + argc_;
}
const char* const *MainOptions::last() const {
return argv_ + argc_ - 1;
}
bool MainOptions::hasKey(const std::string& key) const {
return options_.find(key) != options_.end();
}
MainOptions::Option* MainOptions::getParamFromKey(
const std::string& key) const {
const Options::const_iterator i = options_.find(key);
MainOptions::Option* o = 0;
if (i != options_.end()) {
o = new MainOptions::Option((*i).first, (*i).second);
}
return o;
}
There are these tools in the GNU C Library, which includes GetOpt.
If you are using Qt and like the GetOpt interface, froglogic has published a nice interface here.
Tooting my own horn if I may, I'd also like to suggest taking a look at an option parsing library that I've written: dropt.
It's a C library (with a C++ wrapper if desired).
It's lightweight.
It's extensible (custom argument types can be easily added and have equal footing with built-in argument types).
It should be very portable (it's written in standard C) with no dependencies (other than the C standard library).
It has a very unrestrictive license (zlib/libpng).
One feature that it offers that many others don't is the ability to override earlier options. For example, if you have a shell alias:
alias bar="foo --flag1 --flag2 --flag3"
and you want to use bar but with--flag1 disabled, it allows you to do:
bar --flag1=0
I like C's getopt(), but then I'm old. :-)
Google's gflags
I'd suggest using a library. There's the classic and venerable getopt and I'm sure others.
There are a number of good libraries available.
Boost Program Options is a fairly heavyweight solution, both because adding it to your project requires you to build boost, and the syntax is somewhat confusing (in my opinion). However, it can do pretty much everything including having the command line options override those set in configuration files.
SimpleOpt is a fairly comprehensive but simple command line processor. It is a single file and has a simple structure, but only handles the parsing of the command line into options, you have to do all of the type and range checking. It is good for both Windows and Unix and comes with a version of glob for Windows too.
getopt is available on Windows. It is the same as on Unix machines, but it is often a GPL library.
AnyOption is a C++ class for easy parsing of complex commandline options. It also parses options from a rsourcefile in option value pair format.
AnyOption implements the traditional POSIX style character options ( -n ) as well as the newer GNU style long options ( --name ). Or you can use a simpler long option version ( -name ) by asking to ignore the POSIX style options.
Qt 5.2 comes with a command line parser API.
Small example:
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDebug>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
app.setApplicationName("ToolX");
app.setApplicationVersion("1.2");
QCommandLineParser parser;
parser.setApplicationDescription("Tool for doing X.");
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("infile",
QCoreApplication::translate("main", "Input file."));
QCommandLineOption verbose_opt("+",
QCoreApplication::translate("main", "be verbose"));
parser.addOption(verbose_opt);
QCommandLineOption out_opt(QStringList() << "o" << "output",
QCoreApplication::translate("main", "Output file."),
QCoreApplication::translate("main", "filename"), // value name
QCoreApplication::translate("main", "out") // default value
);
parser.addOption(out_opt);
// exits on error
parser.process(app);
const QStringList args = parser.positionalArguments();
qDebug() << "Input files: " << args
<< ", verbose: " << parser.isSet(verbose_opt)
<< ", output: " << parser.value(out_opt)
<< '\n';
return 0;
}
Example output
The automatically generated help screen:
$ ./qtopt -h
Usage: ./qtopt [options] infile
Tool for doing X.
Options:
-h, --help Displays this help.
-v, --version Displays version information.
-+ be verbose
-o, --output Output file.
Arguments:
infile Input file.
Automatically generated version output:
$ ./qtopt -v
ToolX 1.2
Some real calls:
$ ./qtopt b1 -+ -o tmp blah.foo
Input files: ("b1", "blah.foo") , verbose: true , output: "tmp"
$ ./qtopt
Input files: () , verbose: false , output: "out"
A parse error:
$ ./qtopt --hlp
Unknown option 'hlp'.
$ echo $?
1
Conclusion
If your program already use the Qt (>= 5.2) libraries, its command line parsing API is convenient enough to get the job done.
Be aware that builtin Qt options are consumed by QApplication before the option parser runs.
A command is basically a string. In general it can be split into two parts - the command's name and the command's arguments.
Example:
ls
is used for listing the contents of a directory:
user#computer:~$ ls
Documents Pictures Videos ...
The ls above is executed inside home folder of a user. Here the argument which folder to list is implicitly added to the command. We can explicitly pass some arguments:
user#computer:~$ ls Picture
image1.jpg image2.jpg ...
Here I have explicitly told ls which folder's contents I'd like to see. We can use another argument for example l for listing the details of each file and folder such as access permissions, size etc.:
user#computer:~$ ls Pictures
-rw-r--r-- 1 user user 215867 Oct 12 2014 image1.jpg
-rw-r--r-- 1 user user 268800 Jul 31 2014 image2.jpg
...
Oh, the size looks really weird (215867, 268800). Let's add the h flag for human-friendly output:
user#computer:~$ ls -l -h Pictures
-rw-r--r-- 1 user user 211K Oct 12 2014 image1.jpg
-rw-r--r-- 1 user user 263K Jul 31 2014 image2.jpg
...
Some commands allow their arguments to be combined (in the above case we might as well write ls -lh and we'll get the same output), using short (a single letter usually but sometimes more; abbreviation) or long names (in case of ls we have the -a or --all for listing all files including hidden ones with --all being the long name for -a) etc. There are commands where the order of the arguments is very important but there are also others where the order of the arguments is not important at all.
For example it doesn't matter if I use ls -lh or ls -hl however in the case of mv (moving/renaming files) you have less flexibility for your last 2 arguments that is mv [OPTIONS] SOURCE DESTINATION.
In order to get a grip of commands and their arguments you can use man (example: man ls) or info (example: info ls).
In many languages including C/C++ you have a way of parsing command line arguments that the user has attached to the call of the executable (the command). There are also numerous libraries available for this task since in its core it's actually not that easy to do it properly and at the same time offer a large amount of arguments and their varieties:
getopt
argp_parse
gflags
...
Every C/C++ application has the so called entry point, which is basically where your code starts - the main function:
int main (int argc, char *argv[]) { // When you launch your application the first line of code that is ran is this one - entry point
// Some code here
return 0; // Exit code of the application - exit point
}
No matter if you use a library (like one of the above I've mentioned; but this is clearly not allowed in your case ;)) or do it on your own your main function has the two arguments:
argc - represents the number of arguments
argv - a pointer to an array of strings (you can also see char** argv which is basically the same but more difficult to use).
NOTE: main actually also has a third argument char *envp[] which allows passing environment variables to your command but this is a more advanced thing and I really don't think that it's required in your case.
The processing of command line arguments consists of two parts:
Tokenizing - this is the part where each argument gets a meaning. Its the process of breaking your arguments list into meaningful elements (tokens). In the case of ls -l the l is not only a valid character but also a token in itself since it represents a complete, valid argument.
Here is an example how to output the number of arguments and the (unchecked for validity) characters that may or may not actually be arguments:
#include <iostream>
using std::cout;
using std::endl;
int main (int argc, char *argv[]) {
cout << "Arguments' count=%d" << argc << endl;
// First argument is ALWAYS the command itself
cout << "Command: " << argv[0] << endl;
// For additional arguments we start from argv[1] and continue (if any)
for (int i = 1; i < argc; i++) {
cout << "arg[" << i << "]: " << argv[i] << endl;
}
cout << endl;
return 0;
}
Parsing - after acquiring the tokens (arguments and their values) you need to check if your command supports these. For example:
user#computer:~$ ls -y
will return
ls: invalid option -- 'y'
Try 'ls --help' for more information.
This is because the parsing has failed. Why? Because y (and -y respectively; note that -, --, : etc. is not required and its up to the parsing of the arguments whether you want that stuff there or not; in Unix/Linux systems this is a sort of a convention but you are not bind to it) is an unknown argument for the ls command.
For each argument (if successfully recognized as such) you trigger some sort of change in your application. You can use an if-else for example to check if a certain argument is valid and what it does followed by changing whatever you want that argument to change in the execution of the rest of your code. You can go the old C-style or C++-style:
* `if (strcmp(argv[1], "x") == 0) { ... }` - compare the pointer value
* `if (std::string(argv[1]) == "x") { ... }` - convert to string and then compare
I actually like (when not using a library) to convert argv to an std::vector of strings like this:
std::vector<std::string> args(argv, argv+argc);
for (size_t i = 1; i < args.size(); ++i) {
if (args[i] == "x") {
// Handle x
}
else if (args[i] == "y") {
// Handle y
}
// ...
}
The std::vector<std::string> args(argv, argv+argc); part is just an easier C++-ish way to handle the array of strings since char * is a C-style string (with char *argv[] being an array of such strings) which can easily be converted to a C++ string that is std::string. Then we can add all converted strings to a vector by giving the starting address of argv and then also pointing to its last address namely argv + argc (we add argc number of string to the base address of argv which is basically pointing at the last address of our array).
Inside the for loop above you can see that I check (using simple if-else) if a certain argument is available and if yes then handle it accordingly. A word of caution: by using such a loop the order of the arguments doesn't matter. As I've mentioned at the beginning some commands actually have a strict order for some or all of their arguments. You can handle this in a different way by manually calling the content of each args (or argv if you use the initial char* argv[] and not the vector solution):
// No for loop!
if (args[1] == "x") {
// Handle x
}
else if (args[2] == "y") {
// Handle y
}
// ...
This makes sure that at position 1 only the x will be expected etc. The problem with this is that you can shoot yourself in the leg by going out of bounds with the indexing so you have to make sure that your index stays within the range set by argc:
if (argc > 1 && argc <= 3) {
if (args[1] == "x") {
// Handle x
}
else if (args[2] == "y") {
// Handle y
}
}
The example above makes sure you have content at index 1 and 2 but not beyond.
Last but not least the handling of each argument is a thing that is totally up to you. You can use boolean flags that are set when a certain argument is detected (example: if (args[i] == "x") { xFound = true; } and later on in your code do something based on the bool xFound and its value), numerical types if the argument is a number OR consists of number along with the argument's name (example: mycommand -x=4 has an argument -x=4 which you can additionally parse as x and 4 the last being the value of x) etc. Based on the task at hand you can go crazy and add an insane amount of complexity to your command line arguments.
Hope this helps. Let me know if something is unclear or you need more examples.
I'd recommend boost::program_options if you can use the Boost lib.
There's nothing specific in STL nor in the regular C++/C runtime libs.
argstream is quite similar to boost.program_option: it permits to bind variables to options, etc. However it does not handle options stored in a configuration file.
You could use an already created library for this
http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html
Try CLPP library. It's simple and flexible library for command line parameters parsing. Header-only and cross-platform. Uses ISO C++ and Boost C++ libraries only. IMHO it is easier than Boost.Program_options.
Library: http://sourceforge.net/projects/clp-parser/
26 October 2010 - new release 2.0rc. Many bugs fixed, full refactoring of the source code, documentation, examples and comments have been corrected.
Boost program_options.

GNU argp "too few arguments"

My program is supposed to take two required arguments, and three optional arguments, like follows
ATE <input file> <output file> [--threads] [--bass] [--treble]
(note, I haven't figured out how to take <required> arguments yet, so input and output file is defined in the code as -i input_file and -o output_file)
I'm using the GNU library argp to parse the command line arguments, my file is based off the third example.
I run my program using the following command
$ ./ATE -i input_file.pcm -o output_file.pcm
Too few arguments!
Usage: ATE [OPTION...]
-p AMOUNT_OF_THREADS -b BASS_INTENSITY -t TREBLE_INTENSITY
input_file.pcm output_file.pcm
Try `ATE --help' or `ATE --usage' for more information.
threads: 2, bass: 4, treble: 4
opening file input.pcm
RUNNING!
done, saving to out.pcm
When running my program, I get "too few arguments", even though argp succesfully parsed the input and output option, as you can see in the output.
Printing out the number of arguments in parse_opt, cout << state->arg_num << endl; gives me 0's at every call.
The code is a little long, but it's completely self-contained so you can compile it to see for yourself.
commands.cpp
using namespace std;
#include <stdlib.h>
#include <argp.h>
#include <iostream>
#include <string>
#include <errno.h>
struct arguments {
string input_file;
string output_file;
int threads;
int bass;
int treble;
};
static char doc[] = "Parallequaliser - a multithreaded equaliser application written in c++";
static char args_doc[] = "-p AMOUNT_OF_THREADS -b BASS_INTENSITY -t TREBLE_INTENSITY input_file.pcm output_file.pcm";
static struct argp_option options[] = {
{"input_file", 'i', "IN_FILE", 0, "an input file in pcm format"},
{"output_file", 'o', "OUT_FILE", 0, "an output file in pcm format"},
{"threads", 'p', "AMOUNT_OF_THREADS", OPTION_ARG_OPTIONAL, "amount of threads, min 2"},
{"bass", 'b', "BASS_INTENSITY", OPTION_ARG_OPTIONAL, "bass intensity, from 0 to 7"},
{"treble", 't', "TREBLE_INTENSITY", OPTION_ARG_OPTIONAL, "treble intensity, from 0 to 7"},
{0}
};
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
struct arguments *arguments = (struct arguments *) state->input;
switch (key) {
case 'p':
if (arg == NULL) {
arguments->threads = 4;
} else {
arguments->threads = strtol(arg, NULL, 10);
}
break;
case 'b':
if (arg == NULL) {
arguments->bass = 4;
} else {
arguments->bass = strtol(arg, NULL, 10);
}
break;
case 't':
if (arg == NULL) {
arguments->treble = 4;
} else {
arguments->treble = strtol(arg, NULL, 10);
}
break;
case 'i':
if (arg == NULL) {
cout << "You forgot to specify the input file using the -i input_file.pcm option" << endl;
} else {
arguments->input_file = (string) arg;
}
break;
case 'o':
if (arg == NULL) {
cout << "You forgot to specify the out file using the -i output_file.pcm option" << endl;
} else {
arguments->output_file = (string) arg;
}
break;
case ARGP_KEY_ARG:
cout << "Key arg... " << key << endl;
if (state->arg_num > 5){
cout << "Too many arguments!" << endl;
argp_usage(state);
}
break;
case ARGP_KEY_END:
if (state->arg_num < 2){
cout << "Too few arguments!" << endl;
argp_usage(state);
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = { options, parse_opt, args_doc, doc };
int main (int argc, char **argv) {
struct arguments arguments;
arguments.threads = 2;
arguments.bass = 4;
arguments.treble = 4;
argp_parse(&argp, argc, argv, ARGP_NO_EXIT, 0, &arguments);
cout << "threads: " << arguments.threads << ", bass: " << arguments.bass << ", treble: " << arguments.treble << endl;
cout << "opening file " << arguments.input_file << endl;
cout << "RUNNING!" << endl;
cout << "done, saving to " << arguments.output_file << endl;
return 0;
}
The options don't count as "arguments" for the context of the argp parser.
When running ./ATE -i input_file.pcm -o output_file.pcm, you have "too few arguments" because you reach ARGP_KEY_END, the end of the arguments, with no arguments left. arg_num represents the "stand-alone" arguments : the number of ARGP_KEY_ARG arguments that have been processed. You don't have any.
To make sure you have the two required arguments as you initialy wanted, check that you don't reach ARGP_KEY_END without having seen two arguments (like you are already doing : the too few arguments would mean you don't have your two filenames). The case ARGP_KEY_ARG is where you get the values of the arguments.

Extract parameters from string, included quoted regions, in Qt

I have a Qt5/C++ program which receives a QString containing a program name and possibly parameters. I need to split this QString into multiple strings. For example, the string
/tmp/myprog --param1 --param2=2 --param3="1 2 3" -p 4
Should split into:
list[0]=/tmp/myprog
list[1]=--param1
list[2]=--param2=2
list[3]=--param3="1 2 3"
list[4]=-p 4
My first thought was to use the "split" method on a space, but that would break param3 which is quoted. As well parameter 4 has no : or = between the -p and 4.
Is there a simple way to do this? I suspect the -p 4 is impossible to split up easily since there is no way of knowing if the 2 items below together.
But is there a split/regex/other way to split the above? (If we ignore the -p 4 is it possible?)
Update:
Could the same function split the string without the --param or -p? so a string of
abc "a a" "b b b" c
would become
list[0]=abc
list[1]="a a"
list[2]="b b b"
list[3]=c
There are two aspects of your task:
Splitting of the command line into arguments. This needs to be implemented from scratch.
Processing of the arguments to extract parameters and their values. Since Qt 5.2, you can use QCommandLineParser to do that.
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDebug>
static QStringList splitCommandLine(const QString & cmdLine)
{
QStringList list;
QString arg;
bool escape = false;
enum { Idle, Arg, QuotedArg } state = Idle;
foreach (QChar const c, cmdLine) {
if (!escape && c == '\\') { escape = true; continue; }
switch (state) {
case Idle:
if (!escape && c == '"') state = QuotedArg;
else if (escape || !c.isSpace()) { arg += c; state = Arg; }
break;
case Arg:
if (!escape && c == '"') state = QuotedArg;
else if (escape || !c.isSpace()) arg += c;
else { list << arg; arg.clear(); state = Idle; }
break;
case QuotedArg:
if (!escape && c == '"') state = arg.isEmpty() ? Idle : Arg;
else arg += c;
break;
}
escape = false;
}
if (!arg.isEmpty()) list << arg;
return list;
}
int main(int argc, char * argv[])
{
QCoreApplication app(argc, argv);
QCommandLineParser parser;
parser.addHelpOption();
QCommandLineOption param1("param1");
QCommandLineOption param2("param2", "", "val2");
QCommandLineOption param3("param3", "", "val3");
QCommandLineOption param4("p", "", "val4");
parser.addOption(param1);
parser.addOption(param2);
parser.addOption(param3);
parser.addOption(param4);
if (true) {
// Parse a string
QString cmdLine("/tmp/myprog --param1 --param2=2\\ 2 --param3=\"1 2 3\" -p 4");
parser.parse(splitCommandLine(cmdLine));
} else {
// Parse a command line passed to this application
parser.process(app);
}
if (parser.isSet(param1)) qDebug() << "param1";
if (parser.isSet(param2)) qDebug() << "param2:" << parser.value(param2);
if (parser.isSet(param3)) {
QStringList values = parser.value(param3)
.split(' ', QString::SkipEmptyParts);
qDebug() << "param3:" << values;
}
if (parser.isSet(param4)) qDebug() << "param4:" << parser.value(param4);
return 0;
}
Output:
param1
param2: "2 2"
param3: ("1", "2", "3")
param4: "4"
QDebug quotes the strings it outputs. The strings themselves don't contain any quotes.
I'm not familiar with the particulars of Qt, however with a quick look at the documentation for QString, here, I believe that the following code should work (albeit inefficiently).
#include<QString>
#include<vector>
vector<QString> list; //vector used for variable length parameter requirements
QString args; //The arguments string
bool quoteFlag = false;
for(int i=0; i<args.size(); i++){
QString qstr = "";
while(args.at(i) != QChar(' ') || quoteFlag){ //loops if character is not ' ' or is within a set of quotes
if(args.at(i) == QChar('\"'){
quoteFlag = !quoteflag; //basically says, "you are now within a set of quotes"
}
qstr += args.at(i); //add current character to qstr
i++
}
list.push_back(qstr) //add qstr to the argument list
}
Again, I do not use any Qt libraries, and this code is untested, but, if I understand the documentation, it should work.
As far as the -p 4 bit goes, that is not possible with your current syntax for the other arguments.
Extract parameters from string, included quoted regions, in Qt
When parsing any "escaped" or quoted string: splitArgs (from KF5) was immensely useful.
The following source code manages "escaping" and more; from
one two a\ b "c d e"
it prints
one
two
a b
c d e
The core of the source code is just a splitArgs call:
#include <QTextStream>
#include <KShell>
int main()
{
QString whole = "one two a\\ b \"c d e\"";
QTextStream(stdout) << whole << endl << "--------------------" << endl;
QStringList group = KShell::splitArgs("one two a\\ b \"c d e\"");
for (auto element: group) {
QTextStream(stdout) << element << endl;
}
}
QStringList argumentsList = QProcess::splitCommand(arguments);
https://doc.qt.io/qt-5/qprocess.html#splitCommand

Segmentation Fault with `getopt`

I have a function which handles arguments two three global variables.
It works fine with program -s3, but if I put a space between the s and the argument, I get a segmentation fault even though I'm using atoi to remove whitespace.
Here is the code:
bool handleArgs(int argc, char *argv[])
{
int arg;
bool rtVal = true;
while (true)
{
static struct option long_options[] =
{
{"steps", optional_argument, 0, 's'},
{"walks", optional_argument, 0, 'w'},
{"dimensions", optional_argument, 0, 'd'},
{nullptr, 0, 0, 0}
};
int option_index = 0;
arg = getopt_long (argc, argv, "s::w::d::",long_options, &option_index);
if(arg == -1)
{
break;
}
switch(arg)
{
case 0:
std::cout << long_options[option_index].name << std::endl;
if (optarg)
std::cout << " with arg " << optarg << std::endl;
break;
case 's':
std::cout << "option -s with value " << atoi(optarg) << std::endl;
break;
case 'w':
std::cout << "option -w with value " << atoi(optarg) << std::endl;
break;
case 'd':
std::cout << "option -d with value " << atoi(optarg) << std::endl;
break;
case '?':
/* getopt_long already printed an error message. */
rtVal = false;
break;
default:
rtVal = false;
}
}
return rtVal;
}
In your handler for -s, you don't check for optarg being 0. But you specify two colons after s in your option string: (from man 3 getopt):
Two colons mean an option takes an optional arg; if there is text in the current argv-element (i.e., in the same word as the option name itself, for example, "-oarg"), then it is returned in optarg, otherwise optarg is set to zero. This is a GNU extension.
When the shell starts your program after the invocation program -s 3, it provides three elements in the argv vector:
0: program
1: -s
2: 3
Normally, getopt would interpret this identically to the invocation program -s3, and it's hard to see a reason to change this behaviour. However, gnu helpfully provides you with such an option, allowing you to interpret program -s 3 as a -s option without an argument and a positional argument 3. Once you go down this road, you must check whether optarg is 0 before attempting to use it.
I suspect that you didn't really want to enable this gnu extension. There are very few applications which will benefit from it.

How do I use getopt_long to parse multiple arguments?

#include <iostream>
#include <getopt.h>
#define no_argument 0
#define required_argument 1
#define optional_argument 2
int main(int argc, char * argv[])
{
std::cout << "Hello" << std::endl;
const struct option longopts[] =
{
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"stuff", required_argument, 0, 's'},
{0,0,0,0},
};
int index;
int iarg=0;
//turn off getopt error message
opterr=1;
while(iarg != -1)
{
iarg = getopt_long(argc, argv, "s:vh", longopts, &index);
switch (iarg)
{
case 'h':
std::cout << "You hit help" << std::endl;
break;
case 'v':
std::cout << "You hit version" << std::endl;
break;
case 's':
std::cout << "You hit stuff" << std::endl;
if(optarg)
std::cout << "Your argument(s): " << optarg << std::endl;
break;
}
}
std::cout << "GoodBye!" << std::endl;
return 0;
}
Desired output:
./a.out --stuff someArg1 someArg2
Hello
You hit stuff
Your agument(s): someArg1 someArg2
GoodBye!
getopt returns -1 when all option args have been processed. The --stuff is recognized as an option that takes an argument, in this case someArg1. The someArg2 arg does not start with - or --, so it is not an option. By default, this will be permuted to the end of argv. After getopt returns -1, all non-option args will be in argv from optind to argc-1:
while (iarg != -1) {
iarg = getopt_long(argc, argv, "s:vh", longopts, &index);
// ...
}
for (int i = optind; i < argc; i++) {
cout << "non-option arg: " << argv[i] << std::endl;
}
If you add a single - to the start of optstring, getopt will return 1 (not '1') and point optarg to the non-option parameter:
while (iarg != -1) {
iarg = getopt_long(argc, argv, "-s:vh", longopts, &index);
switch (iarg)
{
// ...
case 1:
std::cout << "You hit a non-option arg:" << optarg << std::endl;
break;
}
}
In the line ./a.out --stuff someArg1 someArg2 the shell interprets three arguments to a.out. You want the shell to interpret "someArg1 someArg2" as one argument - so put the words in quotes:
./a.out --stuff "someArg1 someArg2"
I'm working on windows, so I had to compile getopt and getopt_long from this excellent source
I modified getopt_long.c (below) to accommodate two input arguments. I didn't bother with the more general case of multiple arguments since that would require more (and cleaner) rework than I had time/need for. The second argument is placed in another global, "optarg2".
If you don't need to compile getopt from source, Frank's answer above is more elegant.
extern char * optarg2
.
.
.
int getopt_long(nargc, nargv, options, long_options, index)
{
.
.
.
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument ||
long_options[match].has_arg == two_req_arguments) {
if (has_equal)
optarg = has_equal;
else
optarg = nargv[optind++];
if (long_options[match].has_arg == two_req_arguments) {
optarg2 = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument ||
long_options[match].has_arg == two_req_arguments)
&& (optarg == NULL)) {
/*
* Missing argument, leading :
* indicates no error should be generated
*/
if ((opterr) && (*options != ':'))
(void)fprintf(stderr,
"%s: option requires an argument -- %s\n",
__progname(nargv[0]), current_argv);
return (BADARG);
}
if ((long_options[match].has_arg == two_req_arguments)
&& (optarg2 == NULL)) {
/*
* Missing 2nd argument, leading :
* indicates no error should be generated
*/
if ((opterr) && (*options != ':'))
(void)fprintf(stderr,
"%s: option requires 2nd argument -- %s\n",
__progname(nargv[0]), current_argv);
return (BADARG);
}
You'll also need to add a define in getopt.h for "two_required_args" or "multiple_args" as you see fit.
edit: I'm bad at markdown
optarg points to "someArg1" and argv[optind] is "someArg2" if it exists and is not an option. You can simply use it and then consume it by incrementing optind.
case 's':
std::cout << "You hit stuff" << std::endl;
if (optind < argc && argv[optind][0] != '-') {
std::cout << "Your argument(s): " << optarg << argv[optind] << std::endl;
optind++;
} else {
printusage();
}
break;
Note this can work for an arbitrary number of arguments:
case 's':
std::cout << "You hit stuff." << std::endl;
std::cout << "Your arguments:" std::endl << optarg << std::endl;
while (optind < argc && argv[optind][0] != '-') {
std::cout << argv[optind] << std::endl;
optind++;
}
break;
c++ getopt-long command-line-arguments