Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++, how to use only long options with a required argument?

In a C++ program, I would like to have a "long-only" option with a required argument. Below is my minimal example using getopt_long(), but it's not working:

#include <getopt.h>
#include <cstdlib>
#include <iostream>
using namespace std;

void help (char ** argv)
{
  cout << "`" << argv[0] << "` experiments with long options." << endl;
}

void parse_args (int argc, char ** argv, int & verbose, int & param)
{
  int c = 0;
  while (1)
  {
    static struct option long_options[] =
      {
        {"help", no_argument, 0, 'h'},
        {"verbose", required_argument, 0, 'v'},
        {"param", required_argument, 0, 0}
      };
    int option_index = 0;
    c = getopt_long (argc, argv, "hv:",
                     long_options, &option_index);
    cout << "c=" << c << endl;
    if (c == -1)
      break;
    switch (c)
    {
    case 0:
      if (long_options[option_index].flag != 0)
        break;
      printf ("option %s", long_options[option_index].name);
      if (optarg)
        printf (" with arg %s", optarg);
      printf ("\n");
      break;
    case 'h':
      help (argv);
      exit (0);
    case 'v':
      verbose = atoi(optarg);
      break;
    case 'param':
      param = atoi(optarg);
      break;
    case '?':
      abort ();
    default:
      abort ();
    }
  }
}

int main (int argc, char ** argv)
{
  int verbose = 0;
  int param = 0;
  parse_args (argc, argv, verbose, param);
  cout << "verbose=" << verbose << " param=" << param << endl;
  return EXIT_SUCCESS;
}

I compile it with this command (gcc version 4.1.2 20080704 Red Hat 4.1.2-46):

g++ -Wall test.cpp

It tells me this:

test.cpp:44:10: warning: character constant too long for its type

And here is the result:

$ ./a.out -v 2 --param 3
c=118
c=0
option param with arg 3
c=-1
verbose=2 param=0

I tried to make it work on ideone but it doesn't even recognize the option -v.

As indicated by trojanfoe in his comments of another question, it should be possible to use "long-only" options because GNU tar does it. However, GNU tar uses argp and I have difficulty understanding its source code.

Could someone give me a minimal example that works, with GNU getopt_long() or argp()?

like image 889
tflutre Avatar asked Apr 18 '12 15:04

tflutre


People also ask

What does getopt do in C?

The getopt() function is a builtin function in C and is used to parse command line arguments. Syntax: getopt(int argc, char *const argv[], const char *optstring) optstring is simply a list of characters, each representing a single character option.

What is getopt H?

11.17 getopt. h. Defines the type struct option and declares the variables optarg , optind , opterr , optopt and the functions getopt , getopt_long , getopt_long_only .

What is Optarg getopt?

optarg indicates an optional parameter to a command line option. opterr can be set to 0 to prevent getopt() from printing error messages. optind is the index of the next element of the argument list to be process, and optopt is the command line option last matched.

Can Optarg be null?

Your argument string does not have a : after the X (e.g. X:f) so optarg will always be null.


2 Answers

There are two problems:

  1. According to the example code (your link), the final option defined in the struct must be {0,0,0,0}. I recommend changing the definition to

    static struct option long_options[] =
      {
        {"help", no_argument, 0, 'h'},
        {"verbose", required_argument, 0, 'v'},
        {"param", required_argument, 0, 0},
        {0,0,0,0}
      };
    
  2. (And more importantly,) you must include code that actually processes the "param" option. You do that in the '0' case:

    case 0:
      if (long_options[option_index].flag != 0)
        break;
      if (strcmp(long_options[option_index].name,"param") == 0)
        param = atoi(optarg);
      break;
    

As you can see I use the strcmp function to compare the strings; for that you need to #include <cstring>. By the way, you also need #include <cstdio> for your use of printf.

With these changes in place, the program worked correctly for me (tested on GCC 4.5.1).

like image 163
jogojapan Avatar answered Oct 31 '22 11:10

jogojapan


In your case statement, you are using:

case 'param':

which is giving you the warning, because compiler expects a single character in that place.

like image 36
P.P Avatar answered Oct 31 '22 10:10

P.P