Discovering Command Line Options, Part I

The getopt() function is perhaps one of the most versatile functions I’ve encountered in my C programming journey. It plucks out switches from the list of command line arguments, processing valid ones and spitting out the trash. It’s really quite amazing, but it’s not without its quirks.

Before I knew about getopt(), I coded my own routines to parse command line switches. These typically involved a loop that churned through each argument, comparing it with my slate of valid arguments.

This example is from my version of the robots game. It processes a single argument, which can be any of these options:

--about
--help
-h
--startinglevel=n
-sn

Here is the code:

void searchArgs(int count, char *strings[])
{
    char *s;

    if(count == 1) return;

    count--;

/* Check for About this program */
    if( strcmp(strings[count],"--about") == 0)
        showAbout();

/* Check for Help */
    if( strcmp(strings[count],"--help") == 0)
        showHelp();
    if( strcmp(strings[count],"-h") == 0)
        showHelp();

/* Check for Starting Level option */
    if( strncmp(strings[count],"--startinglevel=",16) == 0)
    {
        s = strings[count];
        s += 16;
        setStarting(strtol(s,NULL,10));
        return;
    }
    if( strncmp(strings[count],"-s",2) == 0)
    {
        s = strings[count];
        s += 2;
        setStarting(strtol(s,NULL,10));
        return;
    }

/* All options exhausted */
    puts("Unknown or misspelled argument");
    showHelp();
}

If the user specified some invalid argument, a warning message is output. This method represents a simple, brute force way to process the single, valid switch. The heavy lifting is done by the strcmp() function. Other functions referenced in the snippet carry out the tasks the switches activate.

The following snippet is from another program. It uses a while loop to process multiple valid switches:

/* check for args */
if(argc)
{
    count = argc;
    while(count--)
    {
        if(strcmp(argv[count],"--verbose") == 0)
            verbose = TRUE;
        if(strcmp(argv[count],"-v") == 0)
            verbose = TRUE;
        if(strcmp(argv[count],"--version") == 0)
        {
            version_info();
            return 99;
        }
        if(strcmp(argv[count],"--help") == 0)
        {
            help_message();
            return 99;
        }
    }
}

This approach again uses the strcmp() function to test for and confirm a valid argument. Options are set, such as verbose = TRUE, for each scan. Duplicate and conflicting arguments aren’t detected, however.

Imagine what horrors would confront you if your program required even more command line switches, including switches with options?

Well, don’t imagine anything. That’s because the getopt() function, as well as its brother getopt_long(), can easily process all the command line switches your program needs. Here is its man page format:

int getopt(int argc, char * const argv[], const char *optstring);

The familiar main() function arguments, argc and argv[] are used in getopt(), which is a blessing. The third argument, optstring, is a string consisting of valid switches. Specifically, the switch letters, which are case-sensitive.

The return value is the tricky part. It’s an integer code from a matching character in the optstring string. If -1 is returned, nothing matched. Further, the function outputs its own error message for an illegal (unspecified) option.

This getopt() function requires you include the unistd.h header file, lest the compiler get cross with you.

Like I wrote earlier, this function is quirky. It helps to run a few sample programs to review how it works. Once you understand what it does, however, you’ll be delighted with its versatility. More details are coming in next week’s Lesson.

Leave a Reply