Question

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.

Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top