Search code examples
ccommand-line-argumentsgetopt

getopt not recognizing multiple command line flags in c


I'm in the process of learning C, and I am trying to get command line flags using getopt() to work. My problem is that it will only recognize the first command flag as a flag, and considers any others as regular command line arguments. Here is my code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[]) {
    char *delivery = "";
    int thick = 0;
    int count = 0;
    char ch;

    while ((ch = getopt(argc, argv, "d:t")) != -1) {
        switch (ch) {
            case 'd':
                delivery = optarg;
                break;
            case 't':
                thick = 1;
                break;
            default:
                fprintf(stderr, "Unknown option: '%s'\n", optarg);
                return 1;
        }
        argc -= optind;
        argv += optind;
    }
    if(thick) {
        puts("Thick crust.");
    }
    if (delivery[0]) {
        printf("To be delivered %s.\n", delivery);
    }
        puts("Ingredients:");
        for(count = 0; count < argc; count++) {
            if (!strstr(argv[count], "./")) {
                puts(argv[count]);
            }
        }
    return 0;
}

When I do one flag or no flags it works completely fine:

$ ./order_pizza Anchovies
Ingredients:
Anchovies

$ ./order_pizza Anchovies Pineapple
Ingredients:
Anchovies
Pineapple

$ ./order_pizza -d now Anchovies Pineapple
To be delivered now.
Ingredients:
Anchovies
Pineapple

$ ./order_pizza -t Anchovies Pineapple
Thick crust.
Ingredients:
Anchovies
Pineapple

However, when I do more than one flag:

$ ./order_pizza -d now -t Anchovies Pineapple
To be delivered now.
Ingredients:
-t
Anchovies
Pineapple

$ ./order_pizza -t -d now Anchovies Pineapple
Thick crust.
Ingredients:
-d
now
Anchovies
Pineapple

I can't seem to figure out what I'm doing wrong, as from my searching no one seems to be having the same issue. I'm on Windows 7 using cygwin and compiling using the following line:

$ gcc order_pizza.c -o order_pizza

Anyone have any ideas?


Solution

  • Don't modify argc and argv inside of the while loop where you call getopt. It uses those variables to do its magic, so changing them messes it up.

    So instead of this:

    while ((ch = getopt(argc, argv, "d:t")) != -1) {
        switch (ch) {
        ...
        }
        argc -= optind;
        argv += optind;
    }
    

    Do this:

    while ((ch = getopt(argc, argv, "d:t")) != -1) {
        switch (ch) {
        ...
        }
    }
    argc -= optind;
    argv += optind;