Search code examples
ccommand-line-argumentsgnugetopt

The simplest possible getopt program I can get?


After doing some reading on this link on how to use getopt(), I'm trying to get a small example.

What I want, is something like:

./prog -v      # show me prog version
./prog -f filename  # just show me the filename I entered from the command line

Here is what I wrote so far:

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

int
main(int argc, *argv[]) {
     char VER[] = "0.1.1";
     int opt;
     opt = getopt(argc, argv, "vf:");
     char *filename;

      while (opt != -1) {
           switch(opt) {
            case 'v':
                printf("version is %s", VER);
                break;
            case 'f':
                filename = optarg;
                break;
            }
     }
    printf("The filename was %s", filename);
    return 0;
}

I compile the code with:

$ gcc prog.c -o prog -Wall -Wextra

I can't seem to understand when I run it with -v option it never stops printing the version and with -f filename it stops there and never prints the filename I entered.


Solution

  • It doesn't stop because you only call getopt() once. A possible fix:

    #include <stdio.h>
    #include <unistd.h>
    
    int
    main(int argc, char **argv)
    {
        char VER[] = "0.1.1";
        int opt;
        const char *filename = "unspecified";
    
        while ((opt = getopt(argc, argv, "vf:")) != -1)
        {
            switch (opt)
            {
                case 'v':
                    printf("version is %s\n", VER);
                    break;
                case 'f':
                    filename = optarg;
                    break;
                default:
                    fprintf(stderr, "Usage: %s [-v][-f file]\n", argv[0]);
                    return(1);
            }
        }
        printf("The filename was %s\n", filename);
        return 0;
    }
    

    Note that I've made sure that filename is initialized, that printf() outputs end with a newline, and that the error cases are reported.

    Here's another, slightly more complex, example program:

    /* Example 1 - using POSIX standard getopt() */
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int
    main(int argc, char **argv)
    {
        int opt;
        int i;
        int bflag = 0;
        int aflag = 0;
        int errflag = 0;
        char *ifile = 0;
        char *ofile = 0;
    
        while ((opt = getopt(argc, argv, ":abf:o:")) != -1)
        {
            switch (opt)
            {
            case 'a':
                if (bflag)
                    errflag++;
                else
                    aflag++;
                break;
            case 'b':
                if (aflag)
                    errflag++;
                else
                    bflag++;
                break;
            case 'f':
                ifile = optarg;
                break;
            case 'o':
                ofile = optarg;
                break;
            case ':':   /* -f or -o without operand */
                fprintf(stderr, "Option -%c requires an operand\n", optopt);
                errflag++;
                break;
            case '?':
            default:
                fprintf(stderr, "Unrecognized option: -%c\n", optopt);
                errflag++;
                break;
            }
        }
    
        if (errflag)
        {
            fprintf(stderr, "Usage: %s [-a|-b][-f in][-o out] [file ...]\n", argv[0]);
            exit(2);
        }
    
        printf("Flags: a = %d, b = %d\n", aflag, bflag);
        if (ifile != 0)
            printf("Input: %s\n", ifile);
        if (ofile != 0)
            printf("Output: %s\n", ofile);
        printf("Argc = %d, OptInd = %d\n", argc, optind);
        for (i = optind; i < argc; i++)
            printf("File: %s\n", argv[i]);
        return(EXIT_SUCCESS);
    }
    

    It is based on an example from a Sun manual. The -a and -b options are mutually exclusive. It illustrates (the limitations of) POSIX getopt() with 'optional arguments' enabled (the leading : on the option string). It also prints out its inputs at the end.