Search code examples
ccommand-linegetopt

Parsing optional command line arguments in C


I have a program that takes in optional arguments. The necessary arguments are a file and integers (1 or more). The optional arguments are a mix of strings and integers.

So a correct input on the command line could be:

./main trace_file 8 12 # (only necessary arguments)

./main –n 3000000 –p page.txt trace_file 8 7 4 # (with optional arguments)

I need to get the integers after trace_file into an array. I'm having trouble figuring out how to do this when the optional arguments are enabled, because another integer is on the command line. A push in the right direction would be greatly appreciated, because I cannot figure out how to do this.

EDIT: so far, all I have for parsing the arguments is this:

for(j=2, k=0; j<argc; j++, k++) {
    shift += atoi(argv[j]);
    shiftArr[k] = 32 - shift;
    bitMaskArr[k] = (int)(pow(2, atoi(argv[j])) - 1) << (shiftArr[k]);
    entryCnt[k] = (int)pow(2, atoi(argv[j]));
}

But this will only work when no optional arguments are entered.


Solution

  • I don't see any major problems if you use a reasonably POSIX-compliant version of getopt().

    Source code (goo.c)

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    /*
       ./main trace_file 8 12 # (only necessary arguments)
    
       ./main –n 3000000 –p page.txt trace_file 8 7 4 # (with optional arguments)
     */
    
    static void usage(const char *argv0)
    {
        fprintf(stderr, "Usage: %s [-n number][-p pagefile] trace n1 n2 ...\n", argv0);
        exit(EXIT_FAILURE);
    }
    
    int main(int argc, char **argv)
    {
        int number = 0;
        char *pagefile = "default.txt";
        char *tracefile;
        int opt;
    
        while ((opt = getopt(argc, argv, "n:p:")) != -1)
        {
            switch (opt)
            {
            case 'p':
                pagefile = optarg;
                break;
            case 'n':
                number = atoi(optarg);
                break;
            default:
                usage(argv[0]);
            }
        }
    
        if (argc - optind < 3)
        {
            fprintf(stderr, "%s: too few arguments\n", argv[0]);
            usage(argv[0]);
        }
    
        tracefile = argv[optind++];
        printf("Trace file: %s\n", tracefile);
        printf("Page file:  %s\n", pagefile);
        printf("Multiplier: %d\n", number);
        for (int i = optind; i < argc; i++)
            printf("Processing number: %d (%s)\n", atoi(argv[i]), argv[i]);
        return 0;
    }
    

    Compilation

    $ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    >      -Wold-style-definition -Werror goo.c -o goo
    

    Example runs

    $ ./goo trace_file 8 12
    Trace file: trace_file
    Page file:  default.txt
    Multiplier: 0
    Processing number: 8 (8)
    Processing number: 12 (12)
    $ ./goo -n 3000000 -p page.txt trace_file 8 7 4
    Trace file: trace_file
    Page file:  page.txt
    Multiplier: 3000000
    Processing number: 8 (8)
    Processing number: 7 (7)
    Processing number: 4 (4)
    $