BRL-CAD
opt.h
Go to the documentation of this file.
1/* O P T . H
2 * BRL-CAD
3 *
4 * Copyright (c) 2015-2023 United States Government as represented by
5 * the U.S. Army Research Laboratory.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * version 2.1 as published by the Free Software Foundation.
10 *
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this file; see the file named COPYING for more
18 * information.
19 */
20
21#ifndef BU_OPT_H
22#define BU_OPT_H
23
24#include "common.h"
25#include "bu/defines.h"
26#include "bu/ptbl.h"
27#include "bu/vls.h"
28
29__BEGIN_DECLS
30
31/** @addtogroup bu_opt
32 * @brief
33 * Generalized option handling.
34 *
35 * This module implements a callback and assignment based mechanism
36 * for generalized handling of option handling. Functionally it is
37 * intended to provide capabilities similar to getopt_long, Qt's
38 * QCommandLineParser, and the tclap library. Results are returned by
39 * way of variable assignment, and function callbacks are used to
40 * convert and validate argument strings.
41 *
42 * The bu_opt option parsing system does not make any use of global
43 * values, unless a user defines an option definition array that
44 * passes in pointers to global variables for setting.
45 *
46 * To set up a bu_opt parsing system, an array of bu_opt_desc (option
47 * description) structures is defined and terminated with a
48 * BU_OPT_DESC_NULL entry. This array is then used by @link
49 * bu_opt_parse @endlink to process an argv array.
50 *
51 * When defining a bu_opt_desc entry, the type of the set_var
52 * assignment variable needed is determined by the arg_process
53 * callback. If no callback is present, set_var is expected to be an
54 * integer that will be set to 1 if the option is present in the argv
55 * string.
56 *
57 * There are two styles in which a bu_opt_desc array may be
58 * initialized. The first is very compact but in C89 based code
59 * requires static variables as set_var entries, as seen in the
60 * following example:
61 *
62 * @code
63 * #define help_str "Print help and exit"
64 * static int ph = 0;
65 * static int i = 0;
66 * static fastf_t f = 0.0;
67 * struct bu_opt_desc opt_defs[] = {
68 * {"h", "help", "", NULL, &ph, help_str},
69 * {"n", "num", "#", &bu_opt_int, &i, "Read int"},
70 * {"f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float"},
71 * BU_OPT_DESC_NULL
72 * };
73 * @endcode
74 *
75 * This style of initialization is suitable for application programs,
76 * but in libraries such static variables will preclude thread and
77 * reentrant safety. For libraries, the BU_OPT and BU_OPT_NULL macros
78 * are used to construct a bu_opt_desc array that does not require
79 * static variables:
80 *
81 * @code
82 * #define help_str "Print help and exit"
83 * int ph = 0;
84 * int i = 0;
85 * fastf_t f = 0.0;
86 * struct bu_opt_desc opt_defs[4];
87 * BU_OPT(opt_defs[0], "h", "help", "", NULL, &ph, help_str);
88 * BU_OPT(opt_defs[1], "n", "num", "#", &bu_opt_int, &i, "Read int");
89 * BU_OPT(opt_defs[2], "f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float");
90 * BU_OPT_NULL(opt_defs[3]);
91 * @endcode
92 *
93 * Given the option description array and argc/argv data, @link
94 * bu_opt_parse @endlink will do the rest. The design of @link
95 * bu_opt_parse @endlink is to fail early when an invalid option
96 * situation is encountered, so code using this system needs to be
97 * ready to handle such cases.
98 *
99 * For generating descriptive help strings from a bu_opt_desc array
100 * use the @link bu_opt_describe @endlink function, which supports
101 * multiple output styles and formats.
102 */
103/** @{ */
104/** @file bu/opt.h */
105
106/**
107 * Callback function signature for bu_opt_desc argument processing
108 * functions. Any user defined argument processing function should
109 * match this signature and return values as documented below.
110 *
111 * @param[out] msg If not NULL, callback messages (usually
112 * error descriptions) may be appended here.
113 * @param[in] argc Number of arguments in argv.
114 * @param[in] argv @em All arguments that follow the option flag.
115 * @param[in, out] set_var The value specified in the associated bu_opt_desc.
116 *
117 * @returns
118 * Val | Interpretation
119 * --- | --------------
120 * -1 | Invalid argument encountered, or argument expected but not found.
121 * 0 | No argument processed (not an error.)
122 * >0 | Number of argv elements used in valid argument processing.
123 *
124 * An example user-defined argument processing function:
125 * @code
126 * static int
127 * parse_opt_mode(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
128 * {
129 * int ret, mode;
130 *
131 * BU_OPT_CHECK_ARGV0(msg, argc, argv, "mode");
132 *
133 * ret = bu_opt_int(msg, argc, argv, set_var);
134 * mode = *(int *)set_var;
135 *
136 * if (mode < 0 || mode > 2) {
137 * ret = -1;
138 * if (msg) {
139 * bu_vls_printf(msg, "Error: mode must be 0, 1, or 2.");
140 * }
141 * }
142 * return ret;
143 * }
144 * @endcode
145 */
146typedef int (*bu_opt_arg_process_t)(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
147
148
149/**
150 * A common task when writing bu_opt_arg_process_t validators is to
151 * check the first argument of the argv array. This macro
152 * encapsulates that into a standard check.
153 */
154#define BU_OPT_CHECK_ARGV0(_msg, _argc, _argv, _opt_name) do { \
155 if ((_argc) < 1 || !(_argv) || !(_argv)[0] || (_argv)[0][0] == '\0') { \
156 if ((_msg)) { \
157 bu_vls_printf((_msg), "ERROR: missing required argument: %s\n", (_opt_name)); \
158 } \
159 return -1; \
160 } \
161 } while (0)
162
163
164/**
165 * @brief
166 * "Option description" structure.
167 *
168 * Arrays of this structure are used to define command line options.
169 */
171 const char *shortopt; /**< @brief "Short" option (i.e. -h for help option) */
172 const char *longopt; /**< @brief "Long" option (i.e. --help for help option) */
173 const char *arg_helpstr; /**< @brief Documentation describing option argument, if any (i.e. "file" in --input file)*/
174 bu_opt_arg_process_t arg_process; /**< @brief Argument processing function pointer */
175 void *set_var; /**< @brief Pointer to the variable or structure that collects this option's results */
176 const char *help_string; /**< @brief Option description */
177};
178
179
180/** Convenience initializer for NULL bu_opt_desc array terminator */
181#define BU_OPT_DESC_NULL {NULL, NULL, NULL, NULL, NULL, NULL}
182
183/** Macro for assigning values to bu_opt_desc array entries. */
184#define BU_OPT(_desc, _so, _lo, _ahelp, _aprocess, _var, _help) do { \
185 (_desc).shortopt = _so; \
186 (_desc).longopt = _lo; \
187 (_desc).arg_helpstr = _ahelp; \
188 (_desc).arg_process = _aprocess; \
189 (_desc).set_var = (void *)_var; \
190 (_desc).help_string = _help; \
191 } while (0)
192
193/** Convenience macro for setting a bu_opt_desc struct to BU_OPT_DESC_NULL */
194#define BU_OPT_NULL(_desc) do { \
195 (_desc).shortopt = NULL; \
196 (_desc).longopt = NULL; \
197 (_desc).arg_helpstr = NULL; \
198 (_desc).arg_process = NULL; \
199 (_desc).set_var = NULL; \
200 (_desc).help_string = NULL; \
201 } while (0)
202
203
204/**
205 * Parse @p argv array using option descriptions.
206 *
207 * The bu_opt_desc array @p ds must be terminated with
208 * BU_OPT_DESC_NULL.
209 *
210 * @returns
211 * Val | Interpretation
212 * --- | --------------
213 * -1 | Fatal error in parsing. Program must decide to recover or exit.
214 * 0 | All argv options handled.
215 * >0 | Number of unused argv entries returned at the beginning of the argv array.
216 *
217 * @param[out] msgs will collect any informational messages
218 * generated by the parser (typically used for
219 * error reporting)
220 * @param[in] ac number of input arguments in argv
221 * @param[in, out] argv a return value >0 indicates that argv has been
222 * reordered to move the indicated number of
223 * unused args to the beginning of the array
224 * @param[in] ds option structure
225 */
226BU_EXPORT extern int bu_opt_parse(struct bu_vls *msgs, size_t ac, const char **argv, const struct bu_opt_desc *ds);
227
228
229/** Output format options for bu_opt documentation generation */
230typedef enum {
232 BU_OPT_DOCBOOK /* TODO */
234
235
236/**
237 * Construct a textual description of the options defined by the
238 * array.
239 *
240 * The structure is as follows:
241 *
242 * Offset Options Descriptions
243 * ******--------------*********************
244 * --test-option This is a test option
245 *
246 * Opt_col specifies how wide the options column is, and desc_cols
247 * specifies how wide the description column is.
248 *
249 * This structure is currently experimental and likely will change as
250 * we find out what is needed.
251 */
252
253/* TODO - support actually using the struct... */
259 /* The application needs to inform the printer if certain options
260 * have special status */
264 /* Report the longopt version(s) of an option even when it has a
265 * shortopt */
267 /* It may not be desirable to print all options. The caller may
268 * supply a space separated list of options to accept or reject.
269 * Only one list may be supplied at a time. Filtering is either
270 * accept or reject, not both at once.*/
271 const char *accept;
272 const char *reject;
273};
274
275
276/**
277 * initialize an bu_opt_desc_opts struct.
278 *
279 * Out of the box, assume an overall column width of 80 characters.
280 * Given that width, we do a default partitioning. The first three
281 * numbers tell the option printer what column breakout to use for
282 * various components of the lines:
283 *
284 * offset = 2 is the default column offsetting from the left edge
285 * option_columns = The next 28 columns are for printing the option
286 * and its aliases description_columns = The remaining 50 columns are
287 * for human readable explanations of the option
288 *
289 * These values were chosen after some casual
290 * experimentation/observation to see what "looked right" for Linux
291 * command line option printing - if better values (perhaps based on
292 * some OS convention or standard) are available, it would be better
293 * to use those and document their source.
294 */
295#define BU_OPT_DESC_OPTS_INIT_ZERO { BU_OPT_ASCII, 2, 28, 50, NULL, NULL, NULL, 1, NULL, NULL }
296
297/**
298 *
299 * Using the example definition:
300 *
301 * @code
302 * struct bu_opt_desc opt_defs[] = {
303 * {"h", "help", "", NULL, &ph, "Print help string and exit."},
304 * {"n", "num", "#", &bu_opt_int, &i, "Read int"},
305 * {"f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float"},
306 * BU_OPT_DESC_NULL
307 * };
308 * @endcode
309 *
310 * bu_opt_describe would generate the following help string by
311 * default:
312 *
313 @verbatim
314 -h, --help Print help string and exit.
315 -n #, --num # Read int
316 -f #, --fastf_t # Read float
317 @endverbatim
318 *
319 * When multiple options use the same set_var to capture their effect,
320 * they are considered aliases for documentation purposes. For
321 * example, if we add multiple aliases to the help option and make it
322 * more elaborate:
323 *
324 * @code
325 * #define help_str "Print help and exit. If a type is specified to --help, print help specific to that type"
326 * struct help_struct hs;
327 * struct bu_opt_desc opt_defs[] = {
328 * {"h", "help", "[type]", &hfun, &hs, help_str},
329 * {"H", "HELP", "[type]", &hfun, &hs, help_str},
330 * {"?", "", "[type]", &hfun, &hs, help_str},
331 * {"n", "num", "#", &bu_opt_int, &i, "Read int"},
332 * {"f", "fastf_t", "#", &bu_opt_fastf_t, &f, "Read float"},
333 * BU_OPT_DESC_NULL
334 * };
335 * @endcode
336 *
337 * the generated help string reflects this:
338 *
339 @verbatim
340 -h [type], -H [type], -? [type], --help [type], --HELP [type]
341 Print help and exit. If a type is specified to
342 --help, print help specific to that type
343 -n #, --num # Read int
344 -f #, --fastf_t # Read float
345 @endverbatim
346 *
347 * @returns
348 * The generated help string. Note that the string uses allocated
349 * memory and it is the responsibility of the caller to free it with
350 * @link bu_free @endlink.
351 */
352BU_EXPORT extern char *bu_opt_describe(const struct bu_opt_desc *ds, struct bu_opt_desc_opts *settings);
353
354
355/** @} */
356
357/** @addtogroup bu_opt_arg_process
358 *
359 * Standard option validators. If a custom option argument validation isn't
360 * needed, the functions below can be used for most valid data types. When
361 * data conversion is successful, the user_data pointer in bu_opt_data will
362 * point to the results of the string->[type] translation in order to allow a
363 * calling program to use the int/long/etc. without having to repeat the
364 * conversion.
365 *
366 * These functions should return -1 if there was a problem processing the
367 * value, and the number of argv entries processed otherwise. (Some validators
368 * such as bu_opt_color may read different numbers of args depending on what is
369 * found so calling code can't assume a successful validation will always
370 * return 1. Hence -1 is the error return - option validation will never
371 * "revert" previously processed argv entries.)
372 */
373/** @{ */
374
375/**
376 * Process 1 argument to set a boolean type
377 */
378BU_EXPORT extern int bu_opt_bool(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
379
380/**
381 * Process 1 argument to set an integer
382 */
383BU_EXPORT extern int bu_opt_int(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
384
385/**
386 * Process 1 argument to set a long
387 */
388BU_EXPORT extern int bu_opt_long(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
389/**
390 * Process 1 argument (hex style) to set a long
391 */
392BU_EXPORT extern int bu_opt_long_hex(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
393
394/**
395 * Process 1 argument to set a @link fastf_t @endlink (either a float
396 * or a double, depending on how BRL-CAD was compiled)
397 */
398BU_EXPORT extern int bu_opt_fastf_t(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
399
400/**
401 * Process 1 argument to set a char pointer (uses the original argv
402 * string, does not make a copy)
403 */
404BU_EXPORT extern int bu_opt_str(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
405
406/**
407 * Process 1 argument to append to a vls (places a space before the
408 * new entry if the target vls is not empty)
409 */
410BU_EXPORT extern int bu_opt_vls(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
411
412/**
413 * Process 1 or 3 arguments to set a bu_color
414 */
415BU_EXPORT extern int bu_opt_color(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
416
417/**
418 * Process 1 or 3 arguments to set a vect_t
419 */
420BU_EXPORT extern int bu_opt_vect_t(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
421
422/** @} */
423
424/**
425 * Process 0 arguments, incrementing the value held by a long. This is
426 * useful for situations where multiple specifications of identical options are
427 * intended to change output, such as multiple -v options to increase
428 * verbosity.
429 */
430BU_EXPORT extern int bu_opt_incr_long(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
431
432__END_DECLS
433
434#endif /* BU_OPT_H */
435
436/*
437 * Local Variables:
438 * mode: C
439 * tab-width: 8
440 * indent-tabs-mode: t
441 * c-file-style: "stroustrup"
442 * End:
443 * ex: shiftwidth=4 tabstop=8
444 */
Header file for the BRL-CAD common definitions.
int bu_opt_long(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_vect_t(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_str(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_color(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_fastf_t(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_bool(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)
int bu_opt_vls(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_long_hex(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int(* bu_opt_arg_process_t)(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
Definition: opt.h:146
bu_opt_format_t
Definition: opt.h:230
char * bu_opt_describe(const struct bu_opt_desc *ds, struct bu_opt_desc_opts *settings)
int bu_opt_parse(struct bu_vls *msgs, size_t ac, const char **argv, const struct bu_opt_desc *ds)
@ BU_OPT_ASCII
Definition: opt.h:231
@ BU_OPT_DOCBOOK
Definition: opt.h:232
int bu_opt_incr_long(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
struct bu_opt_desc * repeated
Definition: opt.h:262
int option_columns
Definition: opt.h:257
struct bu_opt_desc * optional
Definition: opt.h:263
bu_opt_format_t format
Definition: opt.h:255
int show_all_longopts
Definition: opt.h:266
int description_columns
Definition: opt.h:258
struct bu_opt_desc * required
Definition: opt.h:261
const char * reject
Definition: opt.h:272
int offset
Definition: opt.h:256
const char * accept
Definition: opt.h:271
"Option description" structure.
Definition: opt.h:170
void * set_var
Pointer to the variable or structure that collects this option's results.
Definition: opt.h:175
const char * shortopt
"Short" option (i.e. -h for help option)
Definition: opt.h:171
const char * help_string
Option description.
Definition: opt.h:176
const char * arg_helpstr
Documentation describing option argument, if any (i.e. "file" in –input file)
Definition: opt.h:173
const char * longopt
"Long" option (i.e. –help for help option)
Definition: opt.h:172
bu_opt_arg_process_t arg_process
Argument processing function pointer.
Definition: opt.h:174
Definition: vls.h:53