Linux Application Development (paperback) (2nd Edition)

   

26.1. The Option Table

26.1.1. Defining the Options

Applications provide popt with information on their command-line options through an array of struct poptOption structures.

#include <popt.h> struct poptOption { const char * longName; /* may be NULL */ char shortName; /* may be '\0' */ int argInfo; void * arg; /* depends on argInfo */ int val; /* 0 means do not return, just update flag */ char * descrip; /* optional description of the option */ char * argDescrip; /* optional argument description */ };

Each member of the table defines a single option that may be passed to the program. Long and short options are considered a single option that may occur in two different forms. The first two members, longName and shortName, define the names of the option; the first is a long name, and the latter is a single character.

The argInfo member tells popt what type of argument is expected after the argument. If no option is expected, POPT_ARG_NONE should be used. The rest of the valid values are summarized in Table 26.1.[2]

[2] getopt() connoisseurs will note that argInfo is the only required member of struct poptOption that is not directly analogous to a member in the getopt_long() argument table. The similarity between the two allows for easy transitions from getopt_long() to popt.

Table 26.1. popt Argument Types

Value

Description

arg Type

POPT_ARG_NONE

No argument is expected

int

POPT_ARG_STRING

No type checking should be performed

char *

POPT_ARG_INT

An integer argument is expected

int

POPT_ARG_LONG

A long integer is expected

long

POPT_ARG_FLOAT

A float integer is expected

float

POPT_ARG_DOUBLE

A double integer is expected

double

POPT_ARG_VAL

No argument is expected (see text)

int

The next element, arg, allows popt to update program variables automatically when the option is used. If arg is NULL, it is ignored and popt takes no special action. Otherwise, it should point to a variable of the type indicated in the right-most column of Table 26.1.

If the option takes no argument (argInfo is POPT_ARG_NONE), the variable pointed to by arg is set to one when the option is used. If the option does take an argument, the variable that arg points to is updated to reflect the value of the argument. Any string is acceptable for POPT_ARG_STRING arguments, but POPT_ARG_INT, POPT_ARG_LONG, POPT_ARG_FLOAT, and POPT_ARG_DOUBLE arguments are converted to the appropriate type, and an error is returned if the conversion fails.

If POPT_ARG_VAL is used, then no argument is expected. Instead, popt copies the integer value stored in the val member into the address pointed to by arg. This is useful when a program has a set of mutually exclusive arguments, and the last one specified wins. By specifying different val values for each option, having each option's arg member point to the same integer, and specifying POPT_ARG_VAL for each one, it is easy to know which of those options was the last one specified. If you need to give an error if more than one of the options was given, this does not work.

The val member specifies the value popt's parsing function should return when the option is encountered, unless POPT_ARG_VAL is used. If it is zero, the parsing function continues parsing with the next command-line argument rather than return.

The last two members are optional, and should be set to NULL if they are not needed.[3] The first of these, descrip, is a string describing the option. It is used by popt when it generates a help message describing all of the options available. The descrip member provides a sample argument for the option that is also used to display help. Help message generation is described on pages 606-608.

[3] Note that the C language clears all remaining members of a structure that is given a partial default value when it is declared, making this happen automatically in most cases.

The final structure in the table should have all the pointer values set to NULL and all the arithmetic values set to 0, marking the end of the table.

Let's look at how an option table would be defined for a common application. Here is the options table for a simple version of grep utility:[4]

[4] The full source code for this example is on pages 562-567 in Chapter 23.

const char * pattern = NULL; int mode = MODE_REGEXP; int ignoreCase = 0; int maxCount = -1; struct poptOption optionsTable[] = { { "extended-regexp", 'E', POPT_ARG_VAL, &mode, MODE_EXTENDED, "pattern for match is an extended regular expression", NULL }, { "fixed-strings", 'F', POPT_ARG_VAL, &mode, MODE_FIXED, "pattern for match is a basic string (not a " "regular expression)", NULL }, { "basic-regexp", 'G', POPT_ARG_VAL, &mode, MODE_REGEXP, "pattern for match is a basic regular expression" }, { "ignore-case", 'i', POPT_ARG_NONE, &ignoreCase, 0, "perform case insensitive search", NULL }, { "max-count", 'm', POPT_ARG_INT, &maxCount, 0, "terminate after N matches", "N" }, { "regexp", 'e', POPT_ARG_STRING, &pattern, 0, "regular expression to search for", "pattern" }, { NULL, '\0', POPT_ARG_NONE, NULL, 0, NULL, NULL } };

The retry argument does not take an argument, so popt sets the retry variable to one if --retry is specified. The bytes and lines options both take integer arguments, which are stored in the identically named variables. The final option, follow, may be either the literal name or descriptor. The followType variable is set to point to whatever value is given on the command line, and needs to be checked for correctness. By setting it to point to "descriptor" initially, a useful default value is provided.

26.1.2. Nesting Option Tables

Some libraries provide implementation of some common command-line options. For example, one of the original X Windows toolkits handled the -geometry and -display options for applications, giving most X Windows programs a standard set of command-line options for controlling basic behaviors. Unfortunately, there is not an easy way of doing this. Passing argc and argv to an initialization function in the library lets the library handle the appropriate options, but the application has to know to ignore those options when it parses argv. To prevent this problem, XtAppInitialize() took argc and argv as parameters and returned new values for each of them with the options handled by the library removed. This approach, while workable, becomes cumbersome as the number of libraries increases.

To address this, popt allows the nesting of option tables. This lets libraries define the options they want to handle (which could include further nesting), and the main program can provide those options by nesting the libraries option table within its own.

An option table that is going to be nested is defined just like any other one. To include it in another table, a new option is created with empty longName and shortName options. The argInfo field must be set to POPT_ARG_INCLUDE_TABLE and the arg member points to the table to be nested. Here is an example of an option table that includes another:

struct poptOption nestedArgs[] = { { "option1", 'a', POPT_ARG_NONE, NULL, 'a' }, { "option2", 'b', POPT_ARG_NONE, NULL, 'b' }, { NULL, '\0', POPT_ARG_NONE, NULL, 0 } }; struct poptOption mainArgs[] = { { "anoption", 'o', POPT_ARG_NONE, NULL, 'o' }, { NULL, '\0', POPT_ARG_INCLUDE_TABLE, nestedArgs, 0 }, { NULL, '\0', POPT_ARG_NONE, NULL, 0 } };

In this example, the application ends up providing three options, --option1, --option2, and --anoption. A more complete example of nested option tables appears on pages 610-612.


       
     

    Категории