BRL-CAD
Generalized Command-line Option Parsing

Generalized option handling. More...

Collaboration diagram for Generalized Command-line Option Parsing:

Modules

 Pre-Defined Option Parsers
 

Files

file  opt.h
 

Data Structures

struct  bu_opt_desc
 "Option description" structure. More...
 
struct  bu_opt_desc_opts
 

Macros

#define BU_OPT_CHECK_ARGV0(_msg, _argc, _argv, _opt_name)
 
#define BU_OPT_DESC_NULL   {NULL, NULL, NULL, NULL, NULL, NULL}
 
#define BU_OPT(_desc, _so, _lo, _ahelp, _aprocess, _var, _help)
 
#define BU_OPT_NULL(_desc)
 
#define BU_OPT_DESC_OPTS_INIT_ZERO   { BU_OPT_ASCII, 2, 28, 50, NULL, NULL, NULL, 1, NULL, NULL }
 

Typedefs

typedef int(* bu_opt_arg_process_t) (struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
 

Enumerations

enum  bu_opt_format_t { BU_OPT_ASCII , BU_OPT_DOCBOOK }
 

Functions

int bu_opt_parse (struct bu_vls *msgs, size_t ac, const char **argv, const struct bu_opt_desc *ds)
 
char * bu_opt_describe (const struct bu_opt_desc *ds, struct bu_opt_desc_opts *settings)
 

Detailed Description

Generalized option handling.

This module implements a callback and assignment based mechanism for generalized handling of option handling. Functionally it is intended to provide capabilities similar to getopt_long, Qt's QCommandLineParser, and the tclap library. Results are returned by way of variable assignment, and function callbacks are used to convert and validate argument strings.

The bu_opt option parsing system does not make any use of global values, unless a user defines an option definition array that passes in pointers to global variables for setting.

To set up a bu_opt parsing system, an array of bu_opt_desc (option description) structures is defined and terminated with a BU_OPT_DESC_NULL entry. This array is then used by bu_opt_parse to process an argv array.

When defining a bu_opt_desc entry, the type of the set_var assignment variable needed is determined by the arg_process callback. If no callback is present, set_var is expected to be an integer that will be set to 1 if the option is present in the argv string.

There are two styles in which a bu_opt_desc array may be initialized. The first is very compact but in C89 based code requires static variables as set_var entries, as seen in the following example:

#define help_str "Print help and exit"
static int ph = 0;
static int i = 0;
static fastf_t f = 0.0;
struct bu_opt_desc opt_defs[] = {
{"h", "help", "", NULL, &ph, help_str},
{"n", "num", "#", &bu_opt_int, &i, "Read int"},
{"f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float"},
};
int bu_opt_fastf_t(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_int(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
#define BU_OPT_DESC_NULL
Definition: opt.h:181
double fastf_t
fastest 64-bit (or larger) floating point type
Definition: vmath.h:330
"Option description" structure.
Definition: opt.h:170

This style of initialization is suitable for application programs, but in libraries such static variables will preclude thread and reentrant safety. For libraries, the BU_OPT and BU_OPT_NULL macros are used to construct a bu_opt_desc array that does not require static variables:

#define help_str "Print help and exit"
int ph = 0;
int i = 0;
fastf_t f = 0.0;
struct bu_opt_desc opt_defs[4];
BU_OPT(opt_defs[0], "h", "help", "", NULL, &ph, help_str);
BU_OPT(opt_defs[1], "n", "num", "#", &bu_opt_int, &i, "Read int");
BU_OPT(opt_defs[2], "f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float");
BU_OPT_NULL(opt_defs[3]);
#define BU_OPT_NULL(_desc)
Definition: opt.h:194
#define BU_OPT(_desc, _so, _lo, _ahelp, _aprocess, _var, _help)
Definition: opt.h:184

Given the option description array and argc/argv data, bu_opt_parse will do the rest. The design of bu_opt_parse is to fail early when an invalid option situation is encountered, so code using this system needs to be ready to handle such cases.

For generating descriptive help strings from a bu_opt_desc array use the bu_opt_describe function, which supports multiple output styles and formats.

Macro Definition Documentation

◆ BU_OPT_CHECK_ARGV0

#define BU_OPT_CHECK_ARGV0 (   _msg,
  _argc,
  _argv,
  _opt_name 
)
Value:
do { \
if ((_argc) < 1 || !(_argv) || !(_argv)[0] || (_argv)[0][0] == '\0') { \
if ((_msg)) { \
bu_vls_printf((_msg), "ERROR: missing required argument: %s\n", (_opt_name)); \
} \
return -1; \
} \
} while (0)

A common task when writing bu_opt_arg_process_t validators is to check the first argument of the argv array. This macro encapsulates that into a standard check.

Definition at line 154 of file opt.h.

◆ BU_OPT_DESC_NULL

#define BU_OPT_DESC_NULL   {NULL, NULL, NULL, NULL, NULL, NULL}

Convenience initializer for NULL bu_opt_desc array terminator

Definition at line 181 of file opt.h.

◆ BU_OPT

#define BU_OPT (   _desc,
  _so,
  _lo,
  _ahelp,
  _aprocess,
  _var,
  _help 
)
Value:
do { \
(_desc).shortopt = _so; \
(_desc).longopt = _lo; \
(_desc).arg_helpstr = _ahelp; \
(_desc).arg_process = _aprocess; \
(_desc).set_var = (void *)_var; \
(_desc).help_string = _help; \
} while (0)

Macro for assigning values to bu_opt_desc array entries.

Definition at line 184 of file opt.h.

◆ BU_OPT_NULL

#define BU_OPT_NULL (   _desc)
Value:
do { \
(_desc).shortopt = NULL; \
(_desc).longopt = NULL; \
(_desc).arg_helpstr = NULL; \
(_desc).arg_process = NULL; \
(_desc).set_var = NULL; \
(_desc).help_string = NULL; \
} while (0)

Convenience macro for setting a bu_opt_desc struct to BU_OPT_DESC_NULL

Definition at line 194 of file opt.h.

◆ BU_OPT_DESC_OPTS_INIT_ZERO

#define BU_OPT_DESC_OPTS_INIT_ZERO   { BU_OPT_ASCII, 2, 28, 50, NULL, NULL, NULL, 1, NULL, NULL }

initialize an bu_opt_desc_opts struct.

Out of the box, assume an overall column width of 80 characters. Given that width, we do a default partitioning. The first three numbers tell the option printer what column breakout to use for various components of the lines:

offset = 2 is the default column offsetting from the left edge option_columns = The next 28 columns are for printing the option and its aliases description_columns = The remaining 50 columns are for human readable explanations of the option

These values were chosen after some casual experimentation/observation to see what "looked right" for Linux command line option printing - if better values (perhaps based on some OS convention or standard) are available, it would be better to use those and document their source.

Definition at line 295 of file opt.h.

Typedef Documentation

◆ bu_opt_arg_process_t

typedef int(* bu_opt_arg_process_t) (struct bu_vls *msg, size_t argc, const char **argv, void *set_var)

Callback function signature for bu_opt_desc argument processing functions. Any user defined argument processing function should match this signature and return values as documented below.

Parameters
[out]msgIf not NULL, callback messages (usually error descriptions) may be appended here.
[in]argcNumber of arguments in argv.
[in]argvAll arguments that follow the option flag.
[in,out]set_varThe value specified in the associated bu_opt_desc.
Returns
Val Interpretation
-1 Invalid argument encountered, or argument expected but not found.
0 No argument processed (not an error.)
>0 Number of argv elements used in valid argument processing.

An example user-defined argument processing function:

static int
parse_opt_mode(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
{
int ret, mode;
BU_OPT_CHECK_ARGV0(msg, argc, argv, "mode");
ret = bu_opt_int(msg, argc, argv, set_var);
mode = *(int *)set_var;
if (mode < 0 || mode > 2) {
ret = -1;
if (msg) {
bu_vls_printf(msg, "Error: mode must be 0, 1, or 2.");
}
}
return ret;
}
#define BU_OPT_CHECK_ARGV0(_msg, _argc, _argv, _opt_name)
Definition: opt.h:154
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
void int char * mode
Definition: tig.h:179
Definition: vls.h:53

Definition at line 146 of file opt.h.

Enumeration Type Documentation

◆ bu_opt_format_t

Output format options for bu_opt documentation generation

Enumerator
BU_OPT_ASCII 
BU_OPT_DOCBOOK 

Definition at line 230 of file opt.h.

Function Documentation

◆ bu_opt_parse()

int bu_opt_parse ( struct bu_vls msgs,
size_t  ac,
const char **  argv,
const struct bu_opt_desc ds 
)

Parse argv array using option descriptions.

The bu_opt_desc array ds must be terminated with BU_OPT_DESC_NULL.

Returns
Val Interpretation
-1 Fatal error in parsing. Program must decide to recover or exit.
0 All argv options handled.
>0 Number of unused argv entries returned at the beginning of the argv array.
Parameters
[out]msgswill collect any informational messages generated by the parser (typically used for error reporting)
[in]acnumber of input arguments in argv
[in,out]argva return value >0 indicates that argv has been reordered to move the indicated number of unused args to the beginning of the array
[in]dsoption structure

◆ bu_opt_describe()

char * bu_opt_describe ( const struct bu_opt_desc ds,
struct bu_opt_desc_opts settings 
)

Using the example definition:

struct bu_opt_desc opt_defs[] = {
{"h", "help", "", NULL, &ph, "Print help string and exit."},
{"n", "num", "#", &bu_opt_int, &i, "Read int"},
{"f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float"},
};

bu_opt_describe would generate the following help string by default:

-h, --help                    Print help string and exit.
-n #, --num #                 Read int
-f #, --fastf_t #             Read float

When multiple options use the same set_var to capture their effect, they are considered aliases for documentation purposes. For example, if we add multiple aliases to the help option and make it more elaborate:

#define help_str "Print help and exit. If a type is specified to --help, print help specific to that type"
struct help_struct hs;
struct bu_opt_desc opt_defs[] = {
{"h", "help", "[type]", &hfun, &hs, help_str},
{"H", "HELP", "[type]", &hfun, &hs, help_str},
{"?", "", "[type]", &hfun, &hs, help_str},
{"n", "num", "#", &bu_opt_int, &i, "Read int"},
{"f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float"},
};

the generated help string reflects this:

-h [type], -H [type], -? [type], --help [type], --HELP [type]
Print help and exit. If a type is specified to
--help, print help specific to that type
-n #, --num #                 Read int
-f #, --fastf_t #             Read float
Returns
The generated help string. Note that the string uses allocated memory and it is the responsibility of the caller to free it with bu_free.