GNU Long Options Extension

A number of GNU commands like the gcc(1) compiler for example have a large number of options to support. Besides the fact that you can exhaust all possible characters for those options, a user just cannot remember them all. The GNU solution to this problem is the convention of long options.

FreeBSD 3.4 Release includes gcc(1), allowing the following demonstration of a long option:

$ gcc --version
2.7.2.3
$

Long options begin with two hyphens and must be followed by one or more characters. In order to process long options, the GNU function getopt_long(3) must be used.

The GNU getopt_long(3) Function

The getopt_long(3) function will process both the traditional short options and the newer GNU long options. The synopsis for getopt_long(3) is as follows:

#include <getopt.h>

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

The function prototype is almost identical to getopt(3), except for the two new arguments longopts and longindex. The argument longindex points to an integer, where an index value is returned.

Understanding the option Structure

The longopts structure pointer points to the array of option structure entries. The option structure is composed of four members:

  • name points to a C string containing the name of the long option, without the leading hyphens.

  • has_arg is defined as an integer but used as a Boolean value. It must be zero (false) if there is no argument or non-zero (true) if there is an argument for this option.

  • flag either points to an integer or is null.

  • val is used in different ways, depending upon how flag is initialized.

Setting Up the option Structure

The last array entry in the option structure array must be initialized with a null pointer for its name member, zero for the has_arg member, a null pointer for the flag member, and zero for the val member. This entry indicates to getopt_long(3) that there are no more entries in that array. Here is an example of two long options defined in the static option structure long_opts[].

static struct option long_opts[] = {
    {  "help", 0, 0, 'h'} ,    /* name, has_arg, flag, val */
    {  "version", 0, 0, 'v'} , /* name, has_arg, flag, val */
    {  0, 0, 0, 0 }
};

Using a Null option.flag Pointer

The members flag and val of the option structure work together as a team. The easiest way to use these is through the following procedure:

  1. Set flag to null.

  2. Set the int member val to the value that you want getopt_long(3) to return. Often this is the ASCII character code for the equivalent short option letter.

Making a Long Option Look Short

A common practice is to set val to the short option letter equivalent of the long option. For example, if a command supports both --help and -h, then option member flag would be set to a null pointer, and val would be set to the ASCII value 'h'. The structure would be initialized as follows:

static struct option long_opts[] = {
    {  "help", 0, 0, 'h'} , /* name, has_arg, flag, val */
    {  0, 0, 0, 0 }
};

Processing when the option.flag Pointer Is Null

When processing the long option --help, the getopt_long(3) function performs the following basic steps:

  1. The getopt_long(3) scans the long_opts[] array, using an index that we will call x. It will start with x=0.

  2. A strcmp(3) is done to see if our option string "help" matches the entry in long_opts[x].name (x is currently the value zero). Note that the hyphens are already stripped off the option string.

  3. The strcmp(3) function returns zero because the strings match.

  4. Now getopt_long(3) knows the correct index value x. This is returned to the caller by using the integer pointer provided in the fifth argument (longindex).

  5. The pointer in long_opts[x].flag is tested for a null pointer. If it is null, then processing proceeds to the next step.

  6. The value of long_opts[x].val is used as the return value for getopt_long(3).

A C code fragment illustrates the last three steps:

*longindex = x;               /* 4. Return array index */
if ( !long_opts[x].flag )     /* 5. if flag is null then */
    return long_opts[x].val;  /* 6. return 'h'*/

Your options loop within your program is now tricked into thinking the -h option was processed instead, because the value 'h' was returned. This is the easiest way to use long options.

Using a Non-Null option.flag Pointer

When the structure option member flag is a non-null pointer, something different happens. First, examine Listing 9.3.

Code Listing 9.3. A Non-Null option.flag Member
1:    static int cmdopt_v = 0;      /* Initialized to false */
2:    static struct option long_opts[] = {
3:        {  "help", 0, 0, 'h'} ,    /* name, has_arg, flag, val */
4:        {  "version", 0, &cmdopt_v, 1 } ,
5:        {  0, 0, 0, 0 }
6:    } ;

Listing 9.3 shows how the variables and the long_opts[] array are declared. The following points explain the reasoning behind this code:

  1. Line 1 declares our -v option flag variable cmdopt_v. It is initialized to false (zero).

  2. Array element long_opts[1] is initialized to accept the long option --version (line 4).

  3. Member long_opts[1].flag (line 4) is initialized with a pointer to our variable cmdopt_v (in line 1).

  4. Member long_opts[1].val (line 4) is initialized with the int value of 1.

  5. Array element long_opts[2] has all members initialized to null or zero. This marks the end of the long options array.

With the declarations arranged as they are in Listing 9.3, the actions of getopt_long(3) when it processes the --version option can be explained.

  1. Internally to getopt_long(3) an array index is initialized to zero. We will call this variable x.

  2. A strcmp(3) is done to see if the option string version matches the entry in long_opts[x].name (x is currently the value zero).

  3. The strcmp(3) function returns non-zero, because the strings do not match (long_opts[0].name points to C string "help").

  4. The getopt_long(3) function increments x to the value 1.

  5. A strcmp(3) is done to see if our option string version matches the entry in long_opts[x].name (x=1).

  6. The strcmp(3) function returns zero, because the option string version matches long_opts[x].name, which also points to a string "version".

  7. Now getopt_long(3) knows the correct index value x. This is returned to the caller by using the integer pointer provided in argument five (longindex) (x=1).

  8. The pointer value long_opts[1].flag is tested to see if it is null. It is not null, so the processing moves on to the next step.

  9. The integer value from long_opts[1].val is fetched and then stored at the location pointed to by long_opts[1].flag.

  10. The getopt_long(3) function returns the value zero to indicate that this special long option has been processed.

Steps 9 and 10 are carried out when the flag member is not null. Step 6 in the list from the "Processing when option.flag Pointer Is Null" section is used when the flag member is null. Note again how getopt_long(3) returns zero in step 10.

The following code fragment summarizes steps 7 through 10 of the procedure:

    *longindex = x;               /* 7. Return array index */
    if ( !long_opts[x].flag )     /* 8. if flag is null */
        return long_opts[x].val;  /*    return val */
    /* Return val via flag ptr */
    *(long_opts[x].flag) = long_opts[x].val; /* 9. Use ptr */
    return 0;                     /* 10. Indicate flag use */
}
						

Note

FreeBSD does not document or include development libraries for getopt_long(3) when Linux extensions are not installed.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.143.4