I'm writing some code for parsing the command line input. The way I use getopt_long is as follows:
int c = 0;
static struct option long_options[] =
{
{"mode", 1, NULL, 'm'},
{"help", 0, NULL, 'h'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "mh", long_options, NULL))!=-1)
{
switch(c)
{
case 0:
{
cerr<<"Usage: ./program <-m> <-h>"<<endl;
exit(1);
break;
}
case 'm':
{
if (!strcmp(optarg, "small"))
mode = 0;
else if (!strcmp(optarg, "medium"))
mode = 1;
else if (!strcmp(optarg, "large"))
mode = 2;
else{
cerr<<"Invalid mode "<<optarg<<endl;
exit(1);
}
break;
}
case 'h':
{
cerr<<"See man page for help."<<endl;
exit(0);
}
default:
{
cerr<<"Unrecognized argument!"<<endl;
exit(1);
}
}
}
I tested the following:
1)
./program
The program doesn't enter the while-loop. Variable c is inspected to be -1.
2)
./program -h
Works well.
3)
./program -m small
The program exit with Segmentation Fault throwing from strcmp().
Thanks for any help.
Here is an example how to parse options with getopt_long()
and correctly handle its return values, such as end of options, missing arguments and unknown options:
struct Options
{
std::string username = "guest";
void parse_command_line(int ac, char** av) try {
enum {
HELP
, USER
};
// This array must be in the same order as the enum.
option const options[] = {
{"help", no_argument, nullptr, HELP}
, {"username", required_argument, nullptr, USER}
, {}
};
::opterr = 0;
for(int c; -1 != (c = getopt_long(ac, av, ":h", options, nullptr));) {
switch(c) {
// both short and long option
case 'h':
case HELP:
usage(av, EXIT_SUCCESS);
break;
// only long option
case USER:
username = ::optarg; //
break;
case ':': // missing argument
throw Exception("--%s: an argument required", options[::optopt].name);
case '?': // unknown option
throw Exception("%s: unknown option", av[optind - 1]);
}
}
}
catch(std::exception& e) {
fprintf(stderr, "error: %s\n", e.what());
usage(av, EXIT_FAILURE);
}
};
Note, that it is not necessary to have a corresponding short option for each long option.