BRL-CAD
opt.h
Go to the documentation of this file.
1 /* O P T . H
2  * BRL-CAD
3  *
4  * Copyright (c) 2015-2024 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  */
146 typedef 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  */
170 struct bu_opt_desc {
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  */
226 BU_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 */
230 typedef 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... */
254 struct bu_opt_desc_opts {
256  int offset;
259  /* The application needs to inform the printer if certain options
260  * have special status */
261  struct bu_opt_desc *required;
262  struct bu_opt_desc *repeated;
264  /* Report the longopt version(s) of an option even when it has a
265  * shortopt */
266  int show_all_longopts;
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  */
352 BU_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  */
378 BU_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  */
383 BU_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  */
388 BU_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  */
392 BU_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  */
398 BU_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  */
404 BU_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  */
410 BU_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  */
415 BU_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  */
420 BU_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  */
430 BU_EXPORT extern int bu_opt_incr_long(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
431 
432 /**
433  * Looking for a string that defines a language per ISO 639-1 language codes.
434  */
435 BU_EXPORT extern int bu_opt_lang(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
436 
437 /**
438  * Look for a valid man page section identifier (for BRL-CAD purposes valid
439  * choices are 1, 3, 5, n)
440  */
441 #define BRLCAD_MAN_SECTIONS {'1', '3', '5', 'n', '\0'}
442 BU_EXPORT extern int bu_opt_man_section(struct bu_vls *msg, size_t argc, const char **argv, void *set_var);
443 
444 __END_DECLS
445 
446 #endif /* BU_OPT_H */
447 
448 /*
449  * Local Variables:
450  * mode: C
451  * tab-width: 8
452  * indent-tabs-mode: t
453  * c-file-style: "stroustrup"
454  * End:
455  * ex: shiftwidth=4 tabstop=8
456  */
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_lang(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
int bu_opt_man_section(struct bu_vls *msg, size_t argc, const char **argv, void *set_var)
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:264
int option_columns
Definition: opt.h:259
struct bu_opt_desc * optional
Definition: opt.h:265
bu_opt_format_t format
Definition: opt.h:257
int show_all_longopts
Definition: opt.h:268
int description_columns
Definition: opt.h:260
struct bu_opt_desc * required
Definition: opt.h:263
const char * reject
Definition: opt.h:274
int offset
Definition: opt.h:258
const char * accept
Definition: opt.h:273
"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