Reputation:
I use getopt_long
on GNU/Linux machine.
Initialize options list as:
static struct option long_options[] = {
{"mode", required_argument, 0, 9},
{0, 0, 0, 0}
};
Have following line of code
c = getopt_long(argc, argv, "", long_options, index_ptr);
When I run my program with command:
prog --mode
Above shown line of code returns '?' in c, but not ':' as expected according to getopt(3)
man page: "Error and -1 returns are the
same as for getopt()"
Yes, when using/parsing short options one could write in options list something like ":m:", so that variable c on missing argument would contain ':', not '?', but what one should do to distinguish between two cases(missing argument, invalid option) when parsing only long options?
How could one distinguish between invalid option and option with missing required argument?
Upvotes: 1
Views: 3934
Reputation: 2944
It is really a bummer that GNU getopt doesn't just return :
in that case :( It got so close to get it right but explicitly tests if there is a :
in the short args string.
In my alternative solution I exploit that optopt
is set to the respective val
. This solves the issue with printing a generalized message for missing option arguments but somehow feels dirty. I have not tested this too much, beware. It does not correctly handle inputs with single -
.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int main(int argc, char *argv[])
{
static int req, opt;
static struct option long_options[] = {
{"req_flag", required_argument, &req, 1},
{"opt_flag", optional_argument, &opt, 1},
{"req", required_argument, NULL, 'r'},
{"opt", optional_argument, NULL, 'o'},
{"none", no_argument, NULL, 'n'},
{0, 0, 0, 0}
};
/* suppress getopt's own error messages */
opterr = 0;
int c, option_index;
while ((c = getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
printf("c=%c (%x), option_index=%d, optind=%d, optopt=%c (%x), optarg='%s'\n",
c, c, option_index, optind, optopt, optopt, optarg);
switch (c) {
case 0:
if (optarg != NULL) {
printf("flag for %s was set to %d (optarg=%s)\n",
long_options[option_index].name, *long_options[option_index].flag, optarg);
// the flag's value is probably useless in the case of req_flag because
// if it is required you probably want to change behavior depending
// on the value of optarg and not just its presence :)
// That (and also handling of optarg of optional flags) would need to
// be done here depending on option_index. I wouldn't recommend using this.
} else {
printf("flag for %s was set to %d\n",
long_options[option_index].name, *long_options[option_index].flag);
}
break;
case 'r':
printf("%s=%s\n", long_options[option_index].name, optarg);
break;
case 'o':
if (optarg == NULL) {
printf("%s given w/o argument\n", long_options[option_index].name);
} else {
printf("%s=%s\n", long_options[option_index].name, optarg);
}
break;
case '?':
if (optopt == 0) {
printf("Invalid option: %s\n", argv[optind-1]);
} else {
printf("Missing argument for long option %s\n", argv[optind-1]);
}
exit(EXIT_FAILURE);
}
}
return 0;
}
Upvotes: 0
Reputation: 21317
The only way that I can see to accomplish your goal of distinguishing between an invalid option and a valid option with a missing argument is to set the has_arg
field of the options struct to optional_argument
, and then to test manually for an argument. Then getopt_long()
will only return a value of '?' when there is an invalid option, and you can check to see if a specified option has an argument by looking in optarg
. Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int main(int argc, char *argv[])
{
int i, opt;
int index = -1;
static struct option long_options[] = {
{"mode", optional_argument, NULL, 'm'},
{0, 0, 0, 0}
};
/* suppress error messages */
//opterr = 0;
while ((opt = getopt_long(argc, argv, "", long_options, &index)) != -1) {
if (opt == '?') {
/* do something, perhaps: */
//printf("Invalid option \n");
// exit(EXIT_FAILURE);
}
if (opt == 'm' && optarg == NULL) {
printf("Missing argument in '--mode' option\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
Upvotes: 3