Reputation: 2694
I'm trying to use long_options[] to parse different options entered from the terminal to a C++ program. My options struct looks like:
static struct option long_options[] = {
// *name, has_arg, *flag, val
{"help", no_argument, 0, 'h'},
{"debug", no_argument, 0, 0},
{"seed", required_argument, 0, 's'},
...
}
Then I'd use getopt_long to read the arguments as follows:
while (true) {
int option_index (0);
int c = getopt_long (argc, argv, "hs:t:iT:N:M:m:V:l:w:P:rR:b:d:a:", long_options, &option_index);
if (c == -1) break;
switch (c) {
case 'h':
print_help ();
case 's':
parameters.seed = atoi(optarg);
break;
case 0:
if (long_options[option_index].flag != 0) break;
else if (strcmp(long_options[option_index].name, "debug") == 0) parameters.debug = true;
...
break;
}
}
The arguments are passed to optarg, which I understand is of type char* or std::string, as shown above.
The problem comes when I think of a way to set an option parameters with a required number of two or more arguments. For instance, I would like to set an option that allows the user to define distribution parameters conveniently. I'd hope this to be called from the terminal as follows:
./program --distribution mean sd
./program --distribution mean sd n
But it seems that long_options expects just one argument by option by default, so sd in the example above is expected to be parsed as a separate option parameter.
How can I change this default behavior? thank you!
Upvotes: 0
Views: 472
Reputation: 5635
Optarg should only be considered as an input.
That said, it is a raw pointer to one of the original argv members.
At the end any remaining unused arguments are regrouped in argv for you to use as, for example input filenames, but, of course, you will have lost their ordering within the arguments.
If you make your own copy of argv at the start, then you could easily find the optarg indicated by getopt, and do your own parsing accepting every argument until the next "-". Getopt will put those additional arguments as "unused".
If you also want to accept any unused arguments, you will need to perform some more filtering of argv to discard the additional options you have used up.
It is messy, but doable relatively safely.
Upvotes: 1
Reputation: 385385
You can't, and it is not conventional to do so.
To give your application an unorthodox command-line arguments structure, you'll have to write your own parser.
A workaround would be to require your users to send their multiple words in one parameter:
./program --distribution 'mean sd n'
though you'd still need to parse this resulting multi-word string yourself.
Boost.ProgramOptions is a little more flexible than old getopt
, without deviating too much from accepted "standard" practice for command-line arguments, but determining whether it does what you want will require research.
Upvotes: 2