Parsing Command Line Arguments in C++?

C++Command Line-Arguments

C++ Problem Overview


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:

C++ Solutions


Solution 1 - C++

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;
}

Solution 2 - C++

Boost.Program_options should do the trick

Solution 3 - C++

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; }
}

Solution 4 - C++

Solution 5 - C++

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;
}

Solution 6 - C++

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.

Solution 7 - C++

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.

Solution 8 - C++

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);
    }

}

Solution 9 - C++

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.

Solution 10 - C++

TCLAP is a really nice lightweight design and easy to use: http://tclap.sourceforge.net/

Solution 11 - C++

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.]

Solution 12 - C++

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.

Solution 13 - C++

And there's a Google library available.

Really, command-line parsing is "solved." Just pick one.

Solution 14 - C++

With C++, the answer is usually in Boost...

Boost.Program Options

Solution 15 - C++

Try Boost::Program Options. It allows you to read and parse command lines as well as config files.

Solution 16 - C++

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;
}

Solution 17 - C++

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.

Solution 18 - C++

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

Solution 19 - C++

I like C's getopt(), but then I'm old. :-)

Solution 20 - C++

Google's gflags

Solution 21 - C++

I'd suggest using a library. There's the classic and venerable getopt and I'm sure others.

Solution 22 - C++

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.

Solution 23 - C++

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.

Solution 24 - C++

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.

Solution 25 - C++

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:

  1. 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;
}

2. 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.

Solution 26 - C++

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.

Solution 27 - C++

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.

Solution 28 - C++

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.

Solution 29 - C++

You could use an already created library for this

http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html

Solution 30 - C++

Solution 31 - C++

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.

Solution 32 - C++

This is my favourite way of doing the command line, especially, but definitely not only when efficiency is an issue. It might seem overkill, but I think there are few disadvantages to this overkill.

Use gperf for efficient C/C++ command line processing

Disadvantages:

  • You have to run a separate tool first to generate the code for a hash table in C/C++
  • No support for specific command line interfaces. For example the posix shorthand system "-xyz" declaring multiple options with one dash would be hard to implement.

Advantages:

  • Your command line options are stored separately from your C++ code (in a separate configuration file, which doesn't need to be read at runtime, only at compile time).
  • All you have in your code is exactly one switch (switching on enum values) to figure out which option you have
  • Efficiency is O(n) where n is the number of options on the command line and the number of possible options is irrelevant. The slowest part is possibly the implementation of the switch (sometimes compilers tend to implement them as if else blocks, reducing their efficiency, albeit this is unlikely if you choose contiguous values, see: this article on switch efficiency )
  • The memory allocated to store the keywords is precisely large enough for the keyword set and no larger.
  • Also works in C

Using an IDE like eclipse you can probably automate the process of running gperf, so the only thing you would have to do is add an option to the config file and to your switch statement and press build...

I used a batch file to run gperf and do some cleanup and add include guards with sed (on the gperf generated .hpp file)...

So, extremely concise and clean code within your software and one auto-generated hash table file that you don't really need to change manually. I doubt if boost::program_options actually would beat that even without efficiency as a priority.

Solution 33 - C++

if this is linux/unix then the standard one to use is gnu getopt

http://www.gnu.org/s/libc/manual/html_node/Getopt.html

Solution 34 - C++

I have used GetPot for some projects: http://getpot.sourceforge.net/

Main feature: everything is in a single header file, no build hassles. Just save it somewhere on your machine and "#include" it in your file holding main()

Hasn't be updated recently, but it is nicely documented, and works well.

Solution 35 - C++

You could try my little options header (166 loc so easily hackable) options.hpp. It is a single header implementation and should do what you ask. It also prints you the help page automatically.

Solution 36 - C++

Following from my comment and from rbaleksandar's answer, the arguments passed to any program in C are string values. You are provided the argument count (argc) which gives you the argument indexes zero-based beginning with the name of the program currently being run (which is always argv[0]). That leaves all arguments between 1 - argc as the user supplied arguments for your program. Each will be a string that is contained in the argument vector (which is a pointer to an array of strings you will seen written as char *argv[], or equivalently as a function parameter char **argv) Each of the strings argv[1] to argv[argc-1] are available to you, you simply need to test which argument is which.

That will allow you to separate, and make them available as the command (cmd), the options (opt) and finally the argument (arg) to your cmd.

Now it is worth noting, that the rules of your shell (bash, etc..) apply to the arguments passed to your program, word-splitting, pathname and variable expansion apply before your code gets the arguments. So you must consider whether single or more commongly double-quoting will be required around any of your arguments to prevent the normal shell splitting that would otherwise apply (e.g. ls -al my file.txt would results in 4 user-supplied arguments to your code, while ls -al "my file.txt" or ls -al my\ file.txt which would result in the 3 your were expecting.

Putting all that together, your short bit of parsing could be done something like what follows. (you are also free to do it however you like, using a switch instead of nested ifs, etc...)

#include <stdio.h>

int main (int argc, char **argv) {
    
    char *cmd = NULL,   /* here, since you are using the arguments  */
         *opt = NULL,   /* themselves, you can simply use a pointer */
         *arg = NULL;   /* or the argument itself without a copy    */
    
    /* looping using the acutal argument index & vector */
    for (int i = 1; i < argc; i++) {
        if (*argv[i] != '-') {      /* checking if the 1st char is - */
            if (!cmd)               /* cmd is currently NULL, and    */
                cmd = argv[i];      /* no '-' it's going to be cmd   */
            else                    /* otherwise, cmd has value, so  */
                arg = argv[i];       /* the value will be opt        */
        }
        else                /* here the value has a leading '-', so  */
            opt = argv[i];  /* it will be the option */
    }
    
    printf ("\n cmd : %s\n opt : %s\n arg : %s\n\n",
            cmd, opt, arg);
            
    return 0;
}

Example Use/Output

If you run the code, you will find it provides separation for the arguments and provides separate pointers to facilitate their use:

$ ./bin/parse_cmd ls -la ./cs3000

 cmd : ls
 opt : -la
 arg : ./cs3000

(it is important to note, that if you were tasked with building a command string where you would need to copy multiple value to say opt or arg, then you could no longer simply use a pointer and would need to create storage, either though a simple declaring of arrays instead of pointer to begin with, or you could dynamically allocate storage as required with, e.g. malloc, calloc and/or realloc. Then you would have storage available to copy and concatenate values within.)

If this was your challenge, then between all the answer here, you should have a handle of how to approach your problem. If you must go further and actually have your program execute the cmd with the opt and the arg, then you will want to look at fork to spawn a semi-separate process within which you run would execute your cmd opt and arg with something similar to execv or execvp. Good luck, and post a comment if you have further questions.

Solution 37 - C++

It's a bit too big to include in a Stack Overflow answer, but I made a library for defining commands lines declaratively. It takes advantage of the the C++14 ability to build up a class constructor by giving initial values to each member variable.

The library is mostly a base class. To define your command syntax, you declare a struct that derives from it. Here's a sample:

struct MyCommandLine : public core::CommandLine {
    Argument<std::string> m_verb{this, "program", "program.exe",
        "this is what my program does"};
    Option<bool> m_help{this, "help", false,
        "displays information about the command line"};
    Alias<bool> alias_help{this, '?', &m_help};
    Option<bool> m_demo{this, "demo", false,
        "runs my program in demonstration mode"};
    Option<bool> m_maximize{this, "maximize", false,
        "opens the main window maximized"};
    Option<int> m_loops{this, "loops", 1,
        "specifies the number of times to repeat"};
    EnumOption<int> m_size{this, "size", 3,
                           { {"s", 1},
                             {"small", 1},
                             {"m", 3},
                             {"med", 3},
                             {"medium", 3},
                             {"l", 5},
                             {"large", 5} } };
    BeginOptionalArguments here{this};
    Argument<std::string> m_file{this, "file-name", "",
        "name of an existing file to open"};
} cl;

The Argument, Option, and Alias class templates are declared in the scope of the CommandLine base class, and you can specialize them for your own types. Each one takes the this pointer, the option name, the default value, and a description for use in printing the command synopsis/usage.

I'm still looking to eliminate the need to sprinkle all the this pointers in there, but I haven't found a way to do it without introducing macros. Those pointers allow each member to register itself with the tables in the base class that drive the parsing.

Once you have an instance, there are several overloads of a method to parse the input from a string or a main-style argument vector. The parser handles both Windows-style and Unix-style option syntax.

if (!cl.Parse(argc, argv)) {
    std::string message;
    for (const auto &error : cl.GetErrors()) {
        message += error + "\n";
    }
    std::cerr << message;
    exit(EXIT_FAILURE);
}

Once it's parsed, you can access the value of any of the options using operator():

if (cl.m_help()) { std::cout << cl.GetUsage(); }
for (int i = 0; i < cl.m_loops(); ++i) { ... }

The whole library is only about 300 lines (excluding tests). The instances are a bit bloaty, since the parsing tables are part of the instance (rather than the class). But you generally only need one instance per program, and the convenience of this purely declarative approach is pretty powerful, and an instance can be reset simply by parsing new input.

Solution 38 - C++

If you don't want to use boost, I'd recommend this little helper class.

Solution 39 - C++

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.

Solution 40 - C++

Your C/C++ program always has a main function. It looks like that:

    int main(int argc, char**argv) {
        ...
    }

Here argc is a number of command line arguments, that have been passed to your program, and argv is an array of strings with these arguments. So command line is separated in-to arguments by the caller process (this is not a single line, like in windows).

Now you need to sort them out:

  • Command name is always the first argument (index 0).
  • Options are just special arguments that specify how a program should work. By convention they start from - sign. Usually - for one letter options and -- for anything longer. So in your task "options" are all arguments, that start from - and are not the 0th.
  • Arguments. Just all other arguments which are not program name or options.

Solution 41 - C++

I am using getopt() under windows/mingw :

while ((c = getopt(myargc, myargv, "vp:d:rcx")) != -1) {
		switch (c) {
		case 'v': // print version
			printf("%s Version %s\n", myargv[0], VERSION);
			exit(0);
			break;
		case 'p': // change local port to listen to
			strncpy(g_portnum, optarg, 10);
			break;
...

Solution 42 - C++

A simple solution is to put argv into a std::map for easy lookups:

map<string, string> argvToMap(int argc, char * argv[])
{
    map<string, string> args;

    for(int i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            const string key = argv[i];
            string value = "";
            if (i+1 < argc && argv[i+1][0] != '-') {
                value = string(argv[i+1]);
                i++;
            }

            args[key] = value;
        }
    }

    return args;
}

Example usage:

#include <map>
#include <string>
#include <iostream>

using namespace std;

map<string, string> argvToMap(int argc, char * argv[])
{
    map<string, string> args;

    for(int i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            const string key = argv[i];
            string value = "";
            if (i+1 < argc && argv[i+1][0] != '-') {
                value = string(argv[i+1]);
                i++;
            }

            args[key] = value;
        }
    }

    return args;
}

void printUsage()
{
    cout << "simple_args: A sample program for simple arg parsing\n"
            "\n"
            "Example usage:\n"
            "    ./simple_args --print-all --option 1 --flag 2\n";
}

int main(int argc, char * argv[])
{
    auto args = argvToMap(argc, argv);

    if (args.count("-h") || args.count("--help")) {
        printUsage();
    }
    else if (args.count("--print-all")) {
        for (auto const & pair: args)
            cout << "{" << pair.first << ": " << pair.second << "}\n";
    }

    return 0;
}

Output:

$ ./simple_args --print-all --option 1 --flag "hello world"
{--flag: hello world}
{--option: 1}
{--print-all: }

There are definitely significant limitations to this approach, but I found it struck a good balance of simplicity and utility.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVerhogenView Question on Stackoverflow
Solution 1 - C++iainView Answer on Stackoverflow
Solution 2 - C++ultramanView Answer on Stackoverflow
Solution 3 - C++naufraghiView Answer on Stackoverflow
Solution 4 - C++Igor SemenovView Answer on Stackoverflow
Solution 5 - C++Matthew FlaschenView Answer on Stackoverflow
Solution 6 - C++Marcin GilView Answer on Stackoverflow
Solution 7 - C++MSBView Answer on Stackoverflow
Solution 8 - C++Oliver NinaView Answer on Stackoverflow
Solution 9 - C++remikzView Answer on Stackoverflow
Solution 10 - C++cheshirekowView Answer on Stackoverflow
Solution 11 - C++j_random_hackerView Answer on Stackoverflow
Solution 12 - C++Dirk EddelbuettelView Answer on Stackoverflow
Solution 13 - C++Max LybbertView Answer on Stackoverflow
Solution 14 - C++FerruccioView Answer on Stackoverflow
Solution 15 - C++thekidderView Answer on Stackoverflow
Solution 16 - C++Luca DavanzoView Answer on Stackoverflow
Solution 17 - C++Dusty CampbellView Answer on Stackoverflow
Solution 18 - C++jamesdlinView Answer on Stackoverflow
Solution 19 - C++John DetersView Answer on Stackoverflow
Solution 20 - C++CraigView Answer on Stackoverflow
Solution 21 - C++Aaron MaenpaaView Answer on Stackoverflow
Solution 22 - C++brofieldView Answer on Stackoverflow
Solution 23 - C++JayView Answer on Stackoverflow
Solution 24 - C++maxschlepzigView Answer on Stackoverflow
Solution 25 - C++rbaleksandarView Answer on Stackoverflow
Solution 26 - C++Luc HermitteView Answer on Stackoverflow
Solution 27 - C++MackeView Answer on Stackoverflow
Solution 28 - C++Denis ShevchenkoView Answer on Stackoverflow
Solution 29 - C++DavidView Answer on Stackoverflow
Solution 30 - C++bobbymcrView Answer on Stackoverflow
Solution 31 - C++Denis ShevchenkoView Answer on Stackoverflow
Solution 32 - C++user1115652View Answer on Stackoverflow
Solution 33 - C++pm100View Answer on Stackoverflow
Solution 34 - C++kebsView Answer on Stackoverflow
Solution 35 - C++burnerView Answer on Stackoverflow
Solution 36 - C++David C. RankinView Answer on Stackoverflow
Solution 37 - C++Adrian McCarthyView Answer on Stackoverflow
Solution 38 - C++StefanView Answer on Stackoverflow
Solution 39 - C++Denis ShevchenkoView Answer on Stackoverflow
Solution 40 - C++Alexey GuseynovView Answer on Stackoverflow
Solution 41 - C++Achim S.View Answer on Stackoverflow
Solution 42 - C++GillespieView Answer on Stackoverflow