Discovering Command Line Options, Part V

Somewhere along the line, shell commands developed longer, verbose versions of their original, short command line switches. So in addition to -o you also could use --output. These switches offer readability and are easier to remember. Alas, the getopt() function doesn’t process them, but its sibling function getopt_long() does.

The getopt_long() function works like getopt(), but allows for switches longer than a single character. These verbose switches are prefixed by two dashes, which aren’t processed by getopt(). The longer switches can be unique or they can map to existing short switches. So your program can use both the -o and --output switches to set the same option; the user can specify either switch.

The format for getopt_long() is the same as for getopt(), but with two additional arguments: the address of an option structure array and an integer index value. Here is the man page format:

int getopt_long(int argc, char * const *argv, const char *optstring,
    const struct option *longopts, int *longindex);

The fourth option, longopts, is the address of an array of option structures. Each structure in the array contains four members that describe the long option:

struct option {
    char *name;
    int has_arg;
    int *flag;
    int val;
};

name is a the option word. This string is the name only; the two dashes are supplied by the user at the command prompt.

has_arg is an int value: 0 or no_argument for options without arguments; 1 or required_argument for options that require an argument; and 2 or optional_argument for an optional argument. Values or the defined constants can be specified.

flag allows the getopt_long() function’s return value to be saved in a specific variable as opposed to being returned from the function directly. Otherwise, specify NULL.

The val member is the value to return when the option is found. The int value can be the same as an existing, single-letter switch. This way you can map a long, verbose switch to an existing, shorter switch.

Though the man page specifies a pointer to the longopts argument, setting the array’s name is sufficient. The last structure in the array is filled with zeros, which is how the function knows it’s read them all. (See the sample code below.)

Unlike the getopts() function, which is defined in the unistd.h header file, getopts_long() is defined in the getopt.h header file.

In the sample code below, the program accepts switches -a, --alpha, --greek, and -z. The -a and --alpha switches represent the same option:

2021_07_24-Lesson.c

#include <stdio.h>
#include <getopt.h>

int main(int argc, char *argv[])
{
    int r;
    struct option args[3] = {
        { "alpha", 0, NULL, 'a' },
        { "greek", 0, NULL, 'g' },
        { 0, 0, 0, 0 }
    };

    /* supress the default error message */
    opterr = 0;

    /* configure long option arguments */

    while( (r=getopt_long(argc,argv,"az",args,0)) != -1 )
    {
        switch(r)
        {
            case 'a':
                /* -a or --alpha argument */
                puts("Option -a or --alpha is set");
                break;
            case 'g':
                /* --greek argument */
                puts("The --greek argument is set");
                break;
            case 'z':
                /* -z argument */
                puts("Option -z is set");
                break;
            case '?':
                printf("Inavlid option: %c\n",optopt);
                break;
            default:
                puts("Unkonwn argument");
        }
    }

    return(0);
}

The getopt_long() function appears at Line 18, embedded in the while loop’s condition. The function’s fourth argument is args, which references the args[] array of option structures defined at Line 7.

Long argument "alpha" is defined in the first structure in the args[] array at Line 8. Structure member 'a' is the value returned when --alpha is specified on the command line. This value is caught with the case statement at Line 22.

Long argument "greek" is defined in the structure at Line 9. It returns argument 'g', caught at Line 26.

At Line 10, the final structure in the array is filled with zeros.

Here are some sample runs:

$ ./a.out -a --greek
Option -a or --alpha is set
The --greek argument is set
$ ./a.out -a --greek -z
Option -a or --alpha is set
The --greek argument is set
Option -z is set
$ ./a.out -g
Inavlid option: g

Long or short, the getopt() and getopt_long() functions help your code process command line switches. Uses these functions is easier than cobbling together your own loops and whatnot, especially when your program requires a variety of switches.

Leave a Reply