user265767
user265767

Reputation: 559

getopt_long() to parse more than one argument to a single option letter

I want to use getopt_long() to parse command-line arguments. After reading the getopt_long() man pages, I have the understanding that getopt_long() only can parse one argument after an option. Is there anyway to use getopt_long() to parse this command line like this:

./a.out -s 127.0.0.1 2012 -u stackoverflow

To give the result:

ip = 127.0.0.1
port = 2012
username = stackoverflow

Here's what I've tried:

while (1) {
    int this_option_optind = optind ? optind : 1;
    int option_index = 0;
    static struct option long_options[] = {
        {"server", required_argument, NULL, 's'},
        {"user", required_argument, NULL, 'u'},
        {0, 0, 0, 0},
    };

    c = getopt_long(argc, argv, "s:u:", long_options, &option_index);
    if (c == -1)
        break;

    switch (c) {

        case 's':
            printf("option %s", long_options[option_index].name);
            if (optarg) {
                printf(" with arg %s", optarg);
            }
            printf("\n");

        case 'u':
            printf("option %s", long_options[option_index].name);
            if (optarg) {
                printf(" with arg %s", optarg);
            }
            printf("\n");

        case '?':
            break;

        default:
            printf("?? getopt returned character code 0%o ??\n", c);
    }
}

Upvotes: 2

Views: 864

Answers (2)

alk
alk

Reputation: 70981

If you'd call your program like this:

./a.out -s "127.0.0.1 2012" -u stackoverflow

you'd be getting "127.0.0.1 2012" as value for optarg in the 's' case.

Upvotes: 0

rici
rici

Reputation: 241931

The first answer is: nothing stops you from using or modifying optind. If optind < argc then optind is the index of the next common-line argument in argv, and otherwise there are no more arguments. So you can use that argument in your processing loop, but it's your responsibility:

  • to ensure that optind is in range (< argc)
  • to check whether the argument at argv[optind] is another option or not (i.e. whether it starts with a -)
  • to increment optind so that the argument you've used doesn't get rescanned by getopt.

The second answer is: you should think three times before doing something non-standard like this. Although it might seem like a bit more typing, there are good reasons to use a more standard technique, like a -p PORT option. It's easier to document, less work to implement, and less surprising for users accustomed to standard command-line option behaviour.

Finally, you're missing a number of break statements in your example code, which is why -s will be reported as also being -u.

Upvotes: 4

Related Questions