Line data Source code
1 : // Copyright (c) 2006-2024 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/advgetopt
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Advanced getopt implementation.
22 : *
23 : * The advgetopt class and implementation is an advanced library to parse
24 : * command line parameters from static definitions specified by the caller.
25 : *
26 : * The class supports the command line options, options found in a default
27 : * configuration file or in a user defined configuration file.
28 : *
29 : * The class also includes support for displaying error messages and help
30 : * information about all the command line arguments.
31 : */
32 :
33 :
34 : /** \mainpage
35 : * The advanced getopt library to handle your command line tools seemlessly.
36 : *
37 : * The library offers an advanced way to parse command line arguments,
38 : * an environment variable, and configuration files in a seamless manner.
39 : * The advgetopt::getopt class is what is used everywhere for that purpose.
40 : *
41 : * The class can be used in a very restrictive mode, meaning that all
42 : * the parameters must clearly be defined by the application. It can also
43 : * be used in a dynamic way where the parameters are dynamically added
44 : * to the list of available options.
45 : *
46 : * The library supports multiple levels in your options. The simplest
47 : * is to use a scope operator like so:
48 : *
49 : * \code
50 : * level1::level2::level3::etc = 123
51 : * \endcode
52 : *
53 : * \note
54 : * The library understands the scope operator (::), the period (.), and
55 : * the slash (/) as level separator. So the following are equivalent.
56 : * Internally, all are changed to the scope operator (::).
57 : *
58 : * \code
59 : * level1::level2::level3::etc = 123
60 : * level1.level2.level3.etc = 123
61 : * level1/level2/level3/etc = 123
62 : * \endcode
63 : *
64 : * The labels in a .ini format (i.e. `[name]` defines sections) are viewed
65 : * as a first level. That name automatically get prepended to the parameters
66 : * appearing under them. Additional levels can be added by using the
67 : * scope operator, again.
68 : *
69 : * \code
70 : * [level1]
71 : * level2::level3::etc = 123
72 : * \endcode
73 : *
74 : * Support for other formats may be added later. For example, we could
75 : * read XML and JSON files. Right now, we are focused on Unix configuration
76 : * files and pretty much never even need two levels.
77 : *
78 : * The library is capable of writing your configuration back to file. It
79 : * will know when a value was modified and only the modified values get
80 : * saved to the read/write configuration file(s). (Either the user file
81 : * or the system file under the `\<proc>.d/...` sub-path.)
82 : */
83 :
84 : // self
85 : //
86 : #include "advgetopt/advgetopt.h"
87 :
88 : #include "advgetopt/exception.h"
89 :
90 :
91 : // snapdev
92 : //
93 : #include <snapdev/join_strings.h>
94 : #include <snapdev/not_reached.h>
95 :
96 :
97 : // cppthread
98 : //
99 : #include <cppthread/log.h>
100 :
101 :
102 : // libutf8
103 : //
104 : #include <libutf8/iterator.h>
105 :
106 :
107 : // C
108 : //
109 : #include <string.h>
110 :
111 :
112 : // last include
113 : //
114 : #include <snapdev/poison.h>
115 :
116 :
117 :
118 :
119 :
120 : /** \brief The advgetopt environment to parse command line options.
121 : *
122 : * This namespace encompasses all the declarations and implementations
123 : * of functions used to parse and access the command line options.
124 : */
125 : namespace advgetopt
126 : {
127 :
128 :
129 : namespace
130 : {
131 :
132 :
133 : /** \brief Definitions of the system options.
134 : *
135 : * The system options are options we add automatically (if the user asked
136 : * for them) and handle automatically when they are found.
137 : *
138 : * The following are the currently supported system options:
139 : *
140 : * \li `--help`
141 : *
142 : * Print out the usage() with most of the command line arguments.
143 : *
144 : * \li '--long-help'
145 : *
146 : * Print all the command line arguments with usage().
147 : *
148 : * The long help is is only added if the list of options include at least
149 : * one group flag (GETOPT_FLAG_SHOW_GROUP1 or GETOPT_FLAG_SHOW_GROUP2).
150 : * See the getopt::parse_options_from_group_names() in advgetopt_usage.cpp.
151 : *
152 : * \li '--\<name>-help'
153 : *
154 : * Print the help from the group named \<name>.
155 : *
156 : * These command line options are added only when groups are defined.
157 : *
158 : * \li `--version`
159 : *
160 : * Print out the version.
161 : *
162 : * \li `--copyright`
163 : *
164 : * Print out the copyright notice.
165 : *
166 : * \li `--license`
167 : *
168 : * Print out the license notice.
169 : *
170 : * \li `--build-date`
171 : *
172 : * Print out the build time and date.
173 : *
174 : * \li `--environment-variable-name`
175 : *
176 : * Print out the build time and date.
177 : *
178 : * \li `--configuration-filenames`
179 : *
180 : * Print out the list of configuration file names that the system checks
181 : * for configuration data.
182 : *
183 : * \li `--path-to-option-definitions`
184 : *
185 : * Print out the path to files which define options for this tool.
186 : *
187 : * \li `--source-option-sources`
188 : *
189 : * Print out all the options and their sources. This shows you where a
190 : * value come from: command line, environment variable, configuration file,
191 : * etc.
192 : *
193 : * \todo
194 : * Add a `--config` option to allow the user to name one specific
195 : * configuration file to use with an executable.
196 : */
197 : option const g_system_options[] =
198 : {
199 : define_option(
200 : Name("build-date")
201 : , Flags(standalone_command_flags<
202 : GETOPT_FLAG_GROUP_COMMANDS
203 : , GETOPT_FLAG_SHOW_SYSTEM>())
204 : , Help("print out the time and date when %p was built and exit.")
205 : ),
206 : define_option(
207 : Name("compiler-version")
208 : , Flags(standalone_command_flags<
209 : GETOPT_FLAG_GROUP_COMMANDS
210 : , GETOPT_FLAG_SHOW_SYSTEM>())
211 : , Help("print the version of the compiler used to compile the advgetopt library.")
212 : ),
213 : define_option(
214 : Name("configuration-filenames")
215 : , Flags(standalone_command_flags<
216 : GETOPT_FLAG_GROUP_COMMANDS
217 : , GETOPT_FLAG_SHOW_SYSTEM>())
218 : , Help("print out the list of configuration files checked out by this tool.")
219 : ),
220 : define_option(
221 : Name("copyright")
222 : , ShortName('C')
223 : , Flags(standalone_command_flags<
224 : GETOPT_FLAG_GROUP_COMMANDS>())
225 : , Help("print out the copyright of %p and exit.")
226 : ),
227 : define_option(
228 : Name("environment-variable-name")
229 : , Flags(standalone_command_flags<
230 : GETOPT_FLAG_GROUP_COMMANDS
231 : , GETOPT_FLAG_SHOW_SYSTEM>())
232 : , Help("print out the name of the environment variable supported by %p (if any.)")
233 : ),
234 : define_option(
235 : Name("has-sanitizer")
236 : , Flags(standalone_command_flags<
237 : GETOPT_FLAG_GROUP_COMMANDS
238 : , GETOPT_FLAG_SHOW_SYSTEM>())
239 : , Help("print whether the advgetopt was compiled with the sanitizer extension.")
240 : ),
241 : define_option(
242 : Name("help")
243 : , ShortName('h')
244 : , Flags(standalone_command_flags<
245 : GETOPT_FLAG_GROUP_COMMANDS
246 : , GETOPT_FLAG_SHOW_USAGE_ON_ERROR>())
247 : , Help("print out this help screen and exit.")
248 : ),
249 : define_option(
250 : Name("license")
251 : , ShortName('L')
252 : , Flags(standalone_command_flags<
253 : GETOPT_FLAG_GROUP_COMMANDS>())
254 : , Help("print out the license of %p and exit.")
255 : ),
256 : define_option(
257 : Name("path-to-option-definitions")
258 : , Flags(standalone_command_flags<
259 : GETOPT_FLAG_GROUP_COMMANDS
260 : , GETOPT_FLAG_SHOW_SYSTEM>())
261 : , Help("print out the path to the option definitions.")
262 : ),
263 : define_option(
264 : Name("print-option")
265 : , Flags(command_flags<
266 : GETOPT_FLAG_GROUP_COMMANDS
267 : , GETOPT_FLAG_REQUIRED
268 : , GETOPT_FLAG_SHOW_SYSTEM>())
269 : , Help("print the value of the named option after parsing all the options from the command line, environment variables, and configuration files.")
270 : ),
271 : define_option(
272 : Name("show-option-sources")
273 : , Flags(standalone_command_flags<
274 : GETOPT_FLAG_GROUP_COMMANDS
275 : , GETOPT_FLAG_SHOW_SYSTEM>())
276 : , Help("parse all the options and then print out the source of each value and each override.")
277 : ),
278 : define_option(
279 : Name("version")
280 : , ShortName('V')
281 : , Flags(standalone_command_flags<
282 : GETOPT_FLAG_GROUP_COMMANDS>())
283 : , Help("print out the version of %p and exit.")
284 : ),
285 : end_options()
286 : };
287 :
288 :
289 : /** \brief Optional list of options.
290 : *
291 : * This optional list of options is added only when the
292 : * f_configuration_filename parameter has a valid filename.
293 : *
294 : * The following are the currently added options:
295 : *
296 : * \li `--config-dir`
297 : *
298 : * This option allows for adding more configuration directories.
299 : * These work the same way as directories defined in the
300 : * f_configuration_directories.
301 : */
302 : option const g_if_configuration_filename_system_options[] =
303 : {
304 : define_option(
305 : Name("config-dir")
306 : , Flags(any_flags<GETOPT_FLAG_COMMAND_LINE
307 : , GETOPT_FLAG_ENVIRONMENT_VARIABLE
308 : , GETOPT_FLAG_REQUIRED
309 : , GETOPT_FLAG_MULTIPLE
310 : , GETOPT_FLAG_GROUP_OPTIONS>())
311 : , Help("add one or more configuration directory paths to search for configuration files.")
312 : ),
313 : end_options()
314 : };
315 :
316 :
317 :
318 :
319 : /** \brief Check whether this parameter is an argument.
320 : *
321 : * An argument is defined as a command line parameter that starts with
322 : * a dash and is not just "-".
323 : *
324 : * Note that "--" is viewed as an argument (this function returns true)
325 : * and the getopt class takes it as a command meaning any other parameter
326 : * is not an argument.
327 : */
328 260 : bool is_arg(char const * a)
329 : {
330 : // "-" and "--" are not options; however "--" returns true
331 : // because after a "--" we take the data as default arguments
332 260 : return a[0] == '-' && a[1] != '\0';
333 : }
334 :
335 :
336 :
337 : /** \brief Check for a "--show-option-sources" flag.
338 : *
339 : * When this flag is defined, we turn on the trace mode in the option_info
340 : * class (which is a global flag). That way we can honor the
341 : * "--show-option-sources" when we are done parsing the configuration files,
342 : * environment variable, and command line.
343 : *
344 : * \param[in] argc The number of items in the \p argv array.
345 : * \param[in] argv The arguments.
346 : */
347 537 : void check_for_show_sources(int argc, char * argv[])
348 : {
349 : static bool found = false;
350 :
351 537 : if(!found && argv != nullptr)
352 : {
353 1107 : for(int idx(1); idx < argc; ++idx)
354 : {
355 714 : if(strcmp(argv[idx], "--show-option-sources") == 0)
356 : {
357 1 : found = true;
358 1 : option_info::set_trace_sources(true);
359 : }
360 : }
361 : }
362 537 : }
363 :
364 :
365 :
366 : } // no name namespace
367 :
368 :
369 :
370 : /** \class getopt_exception
371 : * \brief Base exception of the advgetopt class.
372 : *
373 : * This exception is the base exception of all the advgetopt exceptions.
374 : * Catching this exception allows you to capture all the getopt exceptions.
375 : */
376 :
377 :
378 : /** \class getopt_exception_default
379 : * \brief No default and no value specified.
380 : *
381 : * When a parameter is not specified and no default is available, this
382 : * exception is raised.
383 : */
384 :
385 :
386 : /** \class getopt_exception_undefined
387 : * \brief Attempting to access something that is undefined.
388 : *
389 : * This exception is used when you attempt to access data that was not
390 : * defined. For example, if your tool tries to read parameter "version"
391 : * and that was not defined in the list of options, this exception is
392 : * raised.
393 : */
394 :
395 :
396 : /** \class getopt_exception_invalid
397 : * \brief Attempted to use some invalid data.
398 : *
399 : * This exception is used whenever an attempt is made to access data that
400 : * does not make sense (is invalid.)
401 : *
402 : * For example, the table of options makes use of enumerations for different
403 : * parts. If one of these has a value which does not represent a valid
404 : * enumeration value, then this exception is raised.
405 : */
406 :
407 :
408 : /** \class getopt
409 : * \brief Class used to parse command line options.
410 : *
411 : * This class is the one used by all the wpkg tools to parse the command line
412 : * options. It is very advanced and is capable to read many different types
413 : * of options with a letter (-h) and a word (--verbose) with no parameters,
414 : * one parameter, any number of parameters, and a set of "filenames" (lose
415 : * options that are not specific to an option.)
416 : */
417 :
418 :
419 : /** \struct option
420 : * \brief Structure representing an option.
421 : *
422 : * When creating a getopt() object you have to pass an array of options. That
423 : * array is defined as a set of option structures.
424 : *
425 : * The last option must be an end_options(). It has its f_flags set to
426 : * GETOPT_FLAG_END and all the other parameters are set to zero (i.e. no
427 : * name, no short name, etc.)
428 : *
429 : * Note that with the newer version of the library, you are not expected
430 : * to manually define an array of options. Instead, you want to use the
431 : * C++ functions such as Name(), ShortName(), Flags(), etc. These functions
432 : * are capable of verifying that at least some of the values are valid at
433 : * compile time.
434 : */
435 :
436 :
437 : /** \brief Initialize the getopt object.
438 : *
439 : * \section into Introduction
440 : *
441 : * This constructor initializes a getopt object. It also reads and parses
442 : * the corresponding option configuration file if it exists (based on the
443 : * project name defined in the environment parameter.)
444 : *
445 : * \section program_name Program Name
446 : *
447 : * Once constructed, if you want to have access to the program name, make
448 : * sure to call this function with your `argv` variable:
449 : *
450 : * \code
451 : * opt.parse_program_name(argv);
452 : * \endcode
453 : *
454 : * Remember that the program name is often used in error messages so having
455 : * it defined early is generally a good idea.
456 : *
457 : * \section dynamism Dynamic Options
458 : *
459 : * This constructor is most often used when you want to dynamically add
460 : * options to your executable with the parse_options_info() function.
461 : * For example, the list of options may vary slightly depending on what
462 : * your command is named when launched.
463 : *
464 : * For example:
465 : *
466 : * \code
467 : * if(time(nullptr) & 1)
468 : * {
469 : * opt.parse_options_info(odd_options);
470 : * }
471 : * else
472 : * {
473 : * opt.parse_options_info(even_options);
474 : * }
475 : * \endcode
476 : *
477 : * \section aliases Linking Aliases
478 : *
479 : * After you added all your dynamic options, you want to make sure that
480 : * aliases are linked to the final option. You should always call that
481 : * function because you can't be sure whether someone will add such an
482 : * alias in the .ini option file.
483 : *
484 : * \code
485 : * opt.link_aliases();
486 : * \endcode
487 : *
488 : * You can call this function any number of times. So if you add yet
489 : * more dynamic options at a later time, just make sure to call it
490 : * again in case aliases were added.
491 : *
492 : * \section parse Parse the Arguments
493 : *
494 : * Finally, you want to call the following functions in that order to
495 : * parse the data from configuration files, the environment variable,
496 : * and the list of command line arguments:
497 : *
498 : * \code
499 : * opt.parse_configuration_files();
500 : * opt.parse_environment_variable();
501 : * opt.parse_arguments(argc, argv, option_source_t::SOURCE_COMMAND_LINE);
502 : * \endcode
503 : *
504 : * The order is important because the last command line option found is
505 : * the one kept. So if the same argument is found in the configuration
506 : * file, the environment variable and the command line, the one on the
507 : * command line is kept. In most cases it makes no difference for standalone
508 : * flags, but arguments that expect a parameter will be changed to the last
509 : * specified value.
510 : *
511 : * If you want to determine the configuration filenames, you may use the
512 : * process_configuration_file() function directly instead of the
513 : * parse_configuration_files() function. This also gives you the ability
514 : * to test whether a configuration file was indeed read.
515 : *
516 : * Note that the parse_arguments() last parameter (only_environment_variable)
517 : * is expected to be left along when you call it with `argc` and `argv`.
518 : *
519 : * If you just have a string instead of an `argv` variable, call the
520 : * parse_string() function instead. It will transform your string in an
521 : * array of arguments and then call the parse_arguments() for you.
522 : *
523 : * \attention
524 : * Note that the program name does not get defined until you call the
525 : * parse_program_name() function since that information comes from the
526 : * first arguments of your command line which we do not get on
527 : * construction in this case.
528 : *
529 : * \attention
530 : * Since the arguments are not known to the getopt system yet, the
531 : * GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS is not used in
532 : * this case.
533 : *
534 : * \param[in] opt_env The list of options that your program supports.
535 : *
536 : * \sa link_aliases()
537 : * \sa parse_arguments()
538 : * \sa parse_configuration_files()
539 : * \sa parse_environment_variable()
540 : * \sa parse_string()
541 : * \sa process_configuration_file()
542 : *
543 : * \sa initialize_parser()
544 : * \sa finish_parsing()
545 : */
546 103 : getopt::getopt(options_environment const & opt_env)
547 : {
548 103 : initialize_parser(opt_env);
549 103 : }
550 :
551 :
552 : /** \brief Initialize the getopt object.
553 : *
554 : * The constructor initializes a getopt object and parse the specified
555 : * argv array. If defined, it also parses a configuration file and
556 : * an environment variable.
557 : *
558 : * The order in which parameters are parsed is important since only the
559 : * last value is kept:
560 : *
561 : * \li Each existing configuration file in the order defined in the vector;
562 : * \li The environment variable;
563 : * \li the argv array.
564 : *
565 : * The constructor calls the reset() function to start the parsing. It is
566 : * possible to call the reset() function at any time to parse a new set
567 : * of parameters.
568 : *
569 : * The argv array cannot be nullptr and the array cannot be empty. It must have
570 : * at least one entry representing the program name (argv[0]).
571 : *
572 : * The configuration_files vector can be empty in which case no configuration
573 : * files are read.
574 : *
575 : * The environment_variable_name can be nullptr or the empty string in which case
576 : * it is ignored.
577 : *
578 : * \note
579 : * All the data gets copied while parsed. If the argv array is deleted on
580 : * return, the getopt object remains valid.
581 : *
582 : * \exception getopt_exit
583 : * This function calls finish_parsing() which may throw this exception.
584 : * See that function for details.
585 : *
586 : * \param[in] opt_env The list of options that your program supports.
587 : * \param[in] argc The number of arguments in argv.
588 : * \param[in] argv An array of strings representing arguments.
589 : *
590 : * \sa initialize_parser()
591 : * \sa finish_parsing()
592 : */
593 262 : getopt::getopt(options_environment const & opt_env
594 : , int argc
595 262 : , char * argv[])
596 : {
597 : // TODO: I do not think that this check_for_show_sources() is required
598 : // because we also do it in finish_parsing()
599 : //
600 262 : check_for_show_sources(argc, argv);
601 :
602 262 : initialize_parser(opt_env);
603 252 : finish_parsing(argc, argv);
604 424 : }
605 :
606 :
607 : /** \brief Initialize the parser.
608 : *
609 : * This function is called from the two constructors. It initializes the
610 : * basic options from the user definitions, the file when there is one,
611 : * the group names, and if allowed the system command line options.
612 : *
613 : * This is enough to then parse arguments or configuration files, although
614 : * in most cases this is used to allow for additional environment options
615 : * to be inserted before calling the finish_parsing() function.
616 : *
617 : * \param[in] opt_env The list of options that your program supports.
618 : */
619 365 : void getopt::initialize_parser(options_environment const & opt_env)
620 : {
621 365 : f_variables = std::make_shared<variables>();
622 365 : f_options_environment = opt_env;
623 :
624 365 : parse_options_info(f_options_environment.f_options, false);
625 357 : parse_options_from_file();
626 355 : if(has_flag(GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS | GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS))
627 : {
628 95 : parse_options_info(g_system_options, true);
629 95 : if(f_options_environment.f_configuration_filename != nullptr
630 19 : && *f_options_environment.f_configuration_filename != '\0')
631 : {
632 : // add the "--config-dir <path> ..." option
633 : //
634 16 : parse_options_info(g_if_configuration_filename_system_options, true);
635 : }
636 : }
637 355 : parse_options_from_group_names();
638 :
639 355 : define_environment_variable_data();
640 355 : }
641 :
642 :
643 : /** \brief Actually parse everything.
644 : *
645 : * This function allows you to run the second half of the initialization
646 : * process. We've broken this process up in two, so you can initialize
647 : * a getopt object, add some other options, then finish up the
648 : * initialization process by calling this function.
649 : *
650 : * The command line arguments, configuration files.
651 : *
652 : * \exception getopt_exit
653 : * If the GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS is set and
654 : * a system command was specified on the command, such as --help or
655 : * --version, then that command is run and the function throws this
656 : * exception.
657 : *
658 : * \param[in] argc The number of arguments in argv.
659 : * \param[in] argv An array of strings representing arguments.
660 : */
661 276 : void getopt::finish_parsing(int argc, char * argv[])
662 : {
663 276 : if(argv == nullptr)
664 : {
665 1 : throw getopt_logic_error("argv pointer cannot be nullptr");
666 : }
667 :
668 275 : check_for_show_sources(argc, argv);
669 :
670 275 : parse_program_name(argv);
671 275 : if(f_options_by_name.empty())
672 : {
673 3 : throw getopt_logic_error("an empty list of options is not legal, you must defined at least one (i.e. --version, --help...)");
674 : }
675 :
676 272 : link_aliases();
677 :
678 268 : parse_configuration_files(argc, argv);
679 268 : f_parsed = false;
680 268 : parse_environment_variable();
681 268 : f_parsed = false;
682 268 : parse_arguments(argc, argv, option_source_t::SOURCE_COMMAND_LINE, false);
683 :
684 268 : if(has_flag(GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS))
685 : {
686 14 : flag_t const result(process_system_options(std::cout));
687 14 : if((result & SYSTEM_OPTION_COMMANDS_MASK) != 0)
688 : {
689 7 : throw getopt_exit("system command processed.", 0);
690 : }
691 : }
692 :
693 261 : if(cppthread::log.get_errors() != 0)
694 : {
695 23 : throw getopt_exit("errors were found on your command line, environment variable, or configuration file.", 1);
696 : }
697 238 : }
698 :
699 :
700 : /** \brief Verify that the parser is done.
701 : *
702 : * This function ensures that the parser is done. If the parser is not yet
703 : * done, then the function raises an exception. This allows me to detect
704 : * that I am trying to access a parameter before the whole parsing process
705 : * is done (i.e. I had a call to is_defined("config-dir") happening in the
706 : * configuration handling way before the environment variables and command
707 : * line arguments were parsed, that would never work!)
708 : *
709 : * \exception getopt_initialization
710 : * This exception is raised if the parser is not done yet.
711 : */
712 3254 : void getopt::is_parsed() const
713 : {
714 3254 : if(!f_parsed
715 7 : && (f_options_environment.f_environment_flags & GETOPT_ENVIRONMENT_FLAG_AUTO_DONE) == 0)
716 : {
717 7 : throw getopt_initialization(
718 : "function called too soon, parser is not done yet"
719 : " (i.e. is_defined(), get_string(), get_long(),"
720 14 : " get_double() cannot be called until the parser is done)");
721 : }
722 3247 : }
723 :
724 :
725 : /** \brief Return a reference to the options environment.
726 : *
727 : * This function returns a reference to the options environment that
728 : * was passed to the constructor. This is useful to functions that
729 : * do not otherwise have access to that object.
730 : *
731 : * \return This getopt options environment.
732 : */
733 1 : options_environment const & getopt::get_options_environment() const
734 : {
735 1 : return f_options_environment;
736 : }
737 :
738 :
739 : /** \brief Check whether an environment flag is set or not.
740 : *
741 : * This function checks the environment flags for the specified \p flag.
742 : * When the flag is set, the function returns true.
743 : *
744 : * You may test multiple flags at the same time, if any one of them is set,
745 : * then the function returns true.
746 : *
747 : * \param[in] flag The flag to check out.
748 : *
749 : * \return true if the flag is set.
750 : */
751 769 : bool getopt::has_flag(flag_t flag) const
752 : {
753 769 : return (f_options_environment.f_environment_flags & flag) != 0;
754 : }
755 :
756 :
757 : /** \brief Retrieve the environment variable string.
758 : *
759 : * This function retrieves the environment variable string and saves it
760 : * in the f_environment_variable field. This is used to parse that string
761 : * and add option values, and also by the configuration file loader to see
762 : * whether a --config-dir was used in there.
763 : */
764 356 : void getopt::define_environment_variable_data()
765 : {
766 356 : f_environment_variable.clear();
767 :
768 356 : if(f_options_environment.f_environment_variable_name == nullptr
769 121 : || *f_options_environment.f_environment_variable_name == '\0')
770 : {
771 : // no name
772 : //
773 240 : return;
774 : }
775 :
776 116 : char const * s(getenv(f_options_environment.f_environment_variable_name));
777 116 : if(s == nullptr)
778 : {
779 : // no environment variable with that name
780 : //
781 66 : return;
782 : }
783 :
784 50 : f_environment_variable = s;
785 : }
786 :
787 :
788 : /** \brief Check for an environment variable.
789 : *
790 : * If the name of an environment variable is specified in the option
791 : * environment structure, then it is read as a command line string.
792 : * This function parses the string in an array of strings and then parses
793 : * it as an argv array (just like the argv parameter defined in a main()
794 : * function).
795 : *
796 : * Since the environment variable is checked after the configuration files,
797 : * the options defined in the variable can change the definitions from
798 : * the configuration files.
799 : *
800 : * Like in the configuration files, only options can be specified in the
801 : * environment variable and commands generate an error. The system knows
802 : * since options that can be included in the environment variable are
803 : * marked by the GETOPT_FLAG_ENVIRONMENT_VARIABLE flag. In other words,
804 : * you may allow options to appear on the command line, in configuration
805 : * files, in environment variables or a mix of all of these locations.
806 : *
807 : * \note
808 : * If you change the environment variable between the creation of the
809 : * getopt object and a call to this function, you want to call the
810 : * define_environment_variable_data() again to make sure it can be
811 : * parsed.
812 : */
813 275 : void getopt::parse_environment_variable()
814 : {
815 : // first test the global environment variable
816 : //
817 275 : if(!f_environment_variable.empty())
818 : {
819 52 : parse_string(
820 52 : f_environment_variable
821 : , option_source_t::SOURCE_ENVIRONMENT_VARIABLE
822 : , true);
823 : }
824 :
825 : // second check each option environment variable
826 : //
827 1597 : for(auto const & opt : f_options_by_name)
828 : {
829 1322 : std::string const name(opt.second->get_environment_variable_name());
830 :
831 : // get the value, only set the option if the variable is set
832 : //
833 1322 : std::string value;
834 1322 : if(opt.second->get_environment_variable_value(
835 : value
836 : , f_options_environment.f_environment_variable_intro))
837 : {
838 52 : add_option_from_string(
839 13 : opt.second
840 : , value
841 26 : , std::string()
842 26 : , string_list_t()
843 : , option_source_t::SOURCE_ENVIRONMENT_VARIABLE);
844 : }
845 1322 : }
846 :
847 275 : f_parsed = true;
848 275 : }
849 :
850 :
851 : /** \brief Parse a string similar to a command line argument.
852 : *
853 : * This function parses a line of command line arguments from a string.
854 : * Especially, it is used to parse the environment variable which is
855 : * a string of arguments.
856 : *
857 : * This can be used to parse the command line string as received under
858 : * MS-Windows (i.e. an unparsed one long string of arguments, where
859 : * you also need to do the glob() calls yourself.)
860 : *
861 : * This function actually transforms the input string in an array of
862 : * strings and then calls the parse_arguments() function.
863 : *
864 : * \note
865 : * The input allows for an empty string in which case pretty much nothing
866 : * happens.
867 : *
868 : * \param[in] str The string that is going to be parsed.
869 : * \param[in] source Where the value comes from.
870 : * \param[in] only_environment_variable Whether only options marked with
871 : * the GETOPT_FLAG_ENVIRONMENT_VARIABLE flag are accepted.
872 : */
873 53 : void getopt::parse_string(
874 : std::string const & str
875 : , option_source_t source
876 : , bool only_environment_variable)
877 : {
878 53 : string_list_t args(split_environment(str));
879 53 : if(args.empty())
880 : {
881 : // nothing extra to do
882 : //
883 1 : return;
884 : }
885 :
886 : // TODO: expand the arguments that include unquoted '*', '?', '[...]'
887 : // (note that we remove the quotes at the moment so we'd have
888 : // to keep track of that specific problem...)
889 :
890 : // the argv array has to be a null terminated bare string pointers
891 : //
892 52 : std::vector<char *> sub_argv;
893 :
894 52 : sub_argv.resize(args.size() + 2);
895 :
896 : // argv[0] is the program name
897 : //
898 52 : sub_argv[0] = const_cast<char *>(f_program_fullname.c_str());
899 :
900 : // the other arguments are from the variable
901 : //
902 257 : for(size_t idx(0); idx < args.size(); ++idx)
903 : {
904 205 : sub_argv[idx + 1] = const_cast<char *>(args[idx].c_str());
905 : }
906 :
907 : // this is probably already a nullptr
908 : //
909 52 : sub_argv[args.size() + 1] = nullptr;
910 :
911 : // now convert those parameters in values
912 : //
913 52 : parse_arguments(
914 52 : static_cast<int>(sub_argv.size() - 1)
915 : , sub_argv.data()
916 : , source
917 : , only_environment_variable);
918 53 : }
919 :
920 :
921 : /** \brief Transform a string in an array of arguments.
922 : *
923 : * This function is used to transform a string to an array of arguments
924 : * that can then be used with the parse_arguments() function.
925 : *
926 : * For example, it is used to parse the environment variable string.
927 : *
928 : * \note
929 : * The input string may include quotes. These will be removed. There is
930 : * currently no support for the backslash character.
931 : *
932 : * \param[in] environment The string to be split in arguments.
933 : *
934 : * \return An array of strings.
935 : */
936 58 : string_list_t getopt::split_environment(std::string const & environment)
937 : {
938 : // this is exactly like the command line only in an environment variable
939 : // so parse the parameters just like the shell
940 : //
941 58 : string_list_t args;
942 58 : std::string a;
943 58 : char const * s(environment.c_str());
944 1901 : while(*s != '\0')
945 : {
946 1843 : if(isspace(*s))
947 : {
948 167 : if(!a.empty())
949 : {
950 165 : args.push_back(a);
951 165 : a.clear();
952 : }
953 : do
954 : {
955 168 : ++s;
956 : }
957 168 : while(isspace(*s));
958 : }
959 1676 : else if(*s == '"'
960 1673 : || *s == '\'')
961 : {
962 : // support quotations and remove them from the argument
963 : //
964 5 : char const quote(*s++);
965 5 : while(*s != '\0'
966 182 : && *s != quote)
967 : {
968 177 : a += *s++;
969 : }
970 5 : if(*s != '\0')
971 : {
972 5 : ++s;
973 : }
974 5 : }
975 : else
976 : {
977 1671 : a += *s++;
978 : }
979 : }
980 :
981 58 : if(!a.empty())
982 : {
983 51 : args.push_back(a);
984 : }
985 :
986 116 : return args;
987 58 : }
988 :
989 :
990 : /** \brief Parse an array of arguments.
991 : *
992 : * This function accepts an array of arguments as received by the main()
993 : * function. By default, though, you pass the argc/argv parameters to
994 : * the getopt() constructor which automatically calls this function.
995 : *
996 : * This functin is public so you can call it with additional lists of
997 : * arguments. If that list of arguments comes as a string, you may want
998 : * to call the parse_string() function instead. It will transform your
999 : * string in a list of parameters for you.
1000 : *
1001 : * When the \p only_environment_variable parameter is set to true, then
1002 : * it is considered that the input arguments were found in an environment
1003 : * variables and they are only accepted if the corresponding option
1004 : * definition includes the GETOPT_FLAG_ENVIRONMENT_VARIABLE flag.
1005 : *
1006 : * When the \p only_environment_variable parameter is set to false, the
1007 : * arguments are viewed as command line arguments and the corresponding
1008 : * options must include the GETOPT_FLAG_COMMAND_LINE flag.
1009 : *
1010 : * Variables get overridden by the newest values found in the list of
1011 : * arguments.
1012 : *
1013 : * Note that the command line arguments are the only ones that should
1014 : * include a command (opposed to an option that alters the behavior of
1015 : * your commands.) However, the advgetopt system expects you to properly
1016 : * define what can be used in a configuration file, in an environment
1017 : * variable, or directly on the command line. It is not in charge of
1018 : * that part in itself.
1019 : *
1020 : * \note
1021 : * The code may find some errors in the tables passed to the advgetopt
1022 : * environment (i.e. a duplicate definition.) When such errors are
1023 : * detected, an exception is raised. Errors found on the command line
1024 : * generate a log message. If you setup a callback, you can then decide
1025 : * to either call exit(1) or raise your own exception.
1026 : *
1027 : * \note
1028 : * The function does NOT check whether the list of arguments (argv) is
1029 : * terminated by nullptr. The argc parameter must be correct.
1030 : *
1031 : * \param[in] argc The number of arguments in argv.
1032 : * \param[in] argv The argument strings terminated by a nullptr.
1033 : * \param[in] source Where the value comes from.
1034 : * \param[in] only_environment_variable Accept command line arguments (false)
1035 : * or environment variable arguments (true).
1036 : */
1037 334 : void getopt::parse_arguments(
1038 : int argc
1039 : , char * argv[]
1040 : , option_source_t source
1041 : , bool only_environment_variable)
1042 : {
1043 794 : for(int i(1); i < argc; ++i)
1044 : {
1045 475 : if(argv[i][0] == '-')
1046 : {
1047 409 : if(argv[i][1] == '-')
1048 : {
1049 354 : if(argv[i][2] == '\0')
1050 : {
1051 : // end of options, skip the '--' and then anything else
1052 : // is taken as "filenames" (or whatever the tool expects)
1053 : //
1054 12 : if(f_default_option == nullptr)
1055 : {
1056 2 : cppthread::log << cppthread::log_level_t::error
1057 1 : << "no default options defined; thus \"--\" is not accepted by this program."
1058 2 : << cppthread::end;
1059 1 : break;
1060 : }
1061 :
1062 11 : if(only_environment_variable)
1063 : {
1064 6 : if(!f_default_option->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1065 : {
1066 2 : cppthread::log << cppthread::log_level_t::error
1067 1 : << "option \"--\" is not supported in the environment variable."
1068 2 : << cppthread::end;
1069 1 : break;
1070 : }
1071 : }
1072 : else
1073 : {
1074 5 : if(!f_default_option->has_flag(GETOPT_FLAG_COMMAND_LINE))
1075 : {
1076 2 : cppthread::log << cppthread::log_level_t::error
1077 1 : << "option \"--\" is not supported on the command line."
1078 2 : << cppthread::end;
1079 1 : break;
1080 : }
1081 : }
1082 :
1083 : // in this case we do NOT test whether an argument uses
1084 : // a dash (-) we take them all as default options
1085 : //
1086 23 : while(i + 1 < argc)
1087 : {
1088 14 : ++i;
1089 14 : f_default_option->add_value(argv[i], string_list_t(), source);
1090 : }
1091 : }
1092 : else
1093 : {
1094 : // a long option, check that it is defined in the
1095 : // programmer defined options
1096 : //
1097 684 : std::string option_name(argv[i] + 2);
1098 342 : std::string option_value;
1099 342 : std::string::size_type pos(option_name.find('='));
1100 342 : if(pos != std::string::npos)
1101 : {
1102 21 : if(pos == 0)
1103 : {
1104 2 : cppthread::log << cppthread::log_level_t::error
1105 1 : << "name missing in \""
1106 1 : << argv[i]
1107 1 : << "\"."
1108 2 : << cppthread::end;
1109 1 : break;
1110 : }
1111 :
1112 20 : option_value = option_name.substr(pos + 1);
1113 20 : option_name.resize(pos);
1114 : }
1115 341 : string_list_t option_keys;
1116 341 : option_info::pointer_t opt(get_option(option_name));
1117 340 : if(opt == nullptr)
1118 : {
1119 1 : pos = option_name.find_first_of("[:");
1120 1 : if(pos != std::string::npos)
1121 : {
1122 0 : option_keys = parse_option_map(option_name.substr(pos));
1123 0 : option_name.resize(pos);
1124 0 : opt = get_option(option_name);
1125 : }
1126 1 : if(opt == nullptr)
1127 : {
1128 2 : cppthread::log << cppthread::log_level_t::error
1129 1 : << "option \"--"
1130 1 : << option_name
1131 1 : << "\" is not supported."
1132 2 : << cppthread::end;
1133 1 : break;
1134 : }
1135 0 : if(!opt->has_flag(GETOPT_FLAG_ARRAY))
1136 : {
1137 0 : cppthread::log << cppthread::log_level_t::error
1138 0 : << "option \"--"
1139 0 : << option_name
1140 0 : << "\" does not support the array or map syntax."
1141 0 : << cppthread::end;
1142 0 : break;
1143 : }
1144 0 : if(option_keys.empty())
1145 : {
1146 0 : cppthread::log << cppthread::log_level_t::error
1147 0 : << "option \"--"
1148 0 : << option_name
1149 0 : << "\" has an invalid list of array keys."
1150 0 : << cppthread::end;
1151 0 : break;
1152 : }
1153 : }
1154 339 : if(only_environment_variable)
1155 : {
1156 62 : if(!opt->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1157 : {
1158 2 : cppthread::log << cppthread::log_level_t::error
1159 1 : << "option \"--"
1160 1 : << option_name
1161 1 : << "\" is not supported in the environment variable."
1162 2 : << cppthread::end;
1163 1 : break;
1164 : }
1165 : }
1166 : else
1167 : {
1168 277 : if(!opt->has_flag(GETOPT_FLAG_COMMAND_LINE))
1169 : {
1170 2 : cppthread::log << cppthread::log_level_t::error
1171 1 : << "option \"--"
1172 1 : << option_name
1173 1 : << "\" is not supported on the command line."
1174 2 : << cppthread::end;
1175 1 : break;
1176 : }
1177 : }
1178 337 : if(pos != std::string::npos)
1179 : {
1180 : // the user specified a value after an equal sign
1181 : //
1182 36 : add_option_from_string(
1183 : opt
1184 : , option_value
1185 36 : , std::string()
1186 : , option_keys
1187 : , source);
1188 : }
1189 : else
1190 : {
1191 319 : add_options(opt, i, argc, argv, option_keys, source);
1192 : }
1193 354 : }
1194 : }
1195 : else
1196 : {
1197 55 : if(argv[i][1] == '\0')
1198 : {
1199 : // stdin/stdout (a '-' by itself)
1200 : //
1201 9 : if(f_default_option == nullptr)
1202 : {
1203 2 : cppthread::log << cppthread::log_level_t::error
1204 1 : << "no default options defined; thus \"-\" is not accepted by this program."
1205 2 : << cppthread::end;
1206 1 : break;
1207 : }
1208 8 : if(only_environment_variable)
1209 : {
1210 4 : if(!f_default_option->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1211 : {
1212 2 : cppthread::log << cppthread::log_level_t::error
1213 1 : << "option \"-\" is not supported in the environment variable."
1214 2 : << cppthread::end;
1215 1 : break;
1216 : }
1217 : }
1218 : else
1219 : {
1220 4 : if(!f_default_option->has_flag(GETOPT_FLAG_COMMAND_LINE))
1221 : {
1222 2 : cppthread::log << cppthread::log_level_t::error
1223 1 : << "option \"-\" is not supported on the command line."
1224 2 : << cppthread::end;
1225 1 : break;
1226 : }
1227 : }
1228 :
1229 : // this is similar to a default option by itself
1230 : //
1231 6 : f_default_option->add_value(argv[i], string_list_t(), source);
1232 : }
1233 : else
1234 : {
1235 : // short option(s)
1236 : //
1237 : // i gets incremented by add_options() so we have to
1238 : // keep a copy in `k`
1239 : //
1240 92 : std::string const short_args_string(argv[i] + 1);
1241 46 : for(libutf8::utf8_iterator short_args(short_args_string)
1242 91 : ; short_args != short_args_string.end()
1243 45 : ; ++short_args)
1244 : {
1245 48 : option_info::pointer_t opt(get_option(*short_args));
1246 48 : if(opt == nullptr)
1247 : {
1248 2 : cppthread::log << cppthread::log_level_t::error
1249 1 : << "option \"-"
1250 2 : << short_name_to_string(*short_args)
1251 1 : << "\" is not supported."
1252 3 : << cppthread::end;
1253 1 : break;
1254 : }
1255 47 : if(only_environment_variable)
1256 : {
1257 19 : if(!opt->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1258 : {
1259 2 : cppthread::log << cppthread::log_level_t::error
1260 1 : << "option \"-"
1261 2 : << short_name_to_string(*short_args)
1262 1 : << "\" is not supported in the environment variable."
1263 3 : << cppthread::end;
1264 1 : break;
1265 : }
1266 : }
1267 : else
1268 : {
1269 28 : if(!opt->has_flag(GETOPT_FLAG_COMMAND_LINE))
1270 : {
1271 2 : cppthread::log << cppthread::log_level_t::error
1272 1 : << "option \"-"
1273 2 : << short_name_to_string(*short_args)
1274 1 : << "\" is not supported on the command line."
1275 3 : << cppthread::end;
1276 1 : break;
1277 : }
1278 : }
1279 45 : add_options(opt, i, argc, argv, string_list_t(), source);
1280 48 : }
1281 46 : }
1282 : }
1283 : }
1284 : else
1285 : {
1286 : // direct entry (filename or whatever the tool expects as a default)
1287 : //
1288 66 : if(f_default_option == nullptr)
1289 : {
1290 4 : cppthread::log << cppthread::log_level_t::error
1291 2 : << "no default options defined; we do not know what to do of \""
1292 2 : << argv[i]
1293 2 : << "\"; standalone parameters are not accepted by this program."
1294 4 : << cppthread::end;
1295 2 : break;
1296 : }
1297 64 : if(only_environment_variable)
1298 : {
1299 27 : if(!f_default_option->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1300 : {
1301 2 : cppthread::log << cppthread::log_level_t::error
1302 1 : << "default options are not supported in the environment variable."
1303 2 : << cppthread::end;
1304 1 : break;
1305 : }
1306 : }
1307 : else
1308 : {
1309 37 : if(!f_default_option->has_flag(GETOPT_FLAG_COMMAND_LINE))
1310 : {
1311 2 : cppthread::log << cppthread::log_level_t::error
1312 1 : << "default options are not supported on the command line."
1313 2 : << cppthread::end;
1314 1 : break;
1315 : }
1316 : }
1317 62 : f_default_option->add_value(argv[i], string_list_t(), source);
1318 : }
1319 : }
1320 :
1321 333 : f_parsed = true;
1322 333 : }
1323 :
1324 :
1325 : /** \brief Parse a map following an option name.
1326 : *
1327 : * An option may offer the `ARRAY` capability. This means the option can
1328 : * be used multiple times with a different key as in:
1329 : *
1330 : * \code
1331 : * --name:front 123
1332 : * --name:back 456
1333 : * \endcode
1334 : *
1335 : * The keys in that case are `front` and `back`. The key will be saved
1336 : * along the option value and you can later retrieve the corresponding
1337 : * value using the get_string() with a string representing the key.
1338 : *
1339 : * \code
1340 : * name_front = f_opts.get_string("front"); // returns 123
1341 : * name_back = f_opts.get_string("back"); // returns 456
1342 : * \endcode
1343 : *
1344 : * This function searches for the map key names. The map syntax supports
1345 : * any number of key names either separated by colons or written between
1346 : * square brackets:
1347 : *
1348 : * \code
1349 : * --name[front] 123
1350 : * --name[back] 456
1351 : * \endcode
1352 : *
1353 : * are equivalent to the example above.
1354 : *
1355 : * The map is not limited to one name. At the moment the keys are not
1356 : * verified outside of the requirement of not being empty.
1357 : *
1358 : * The following shows how to define more than one key:
1359 : *
1360 : * \code
1361 : * --name[front][back] 123
1362 : * --name:front:back 123
1363 : * --name[back][front] 123
1364 : * --name:back:front 123
1365 : * \endcode
1366 : *
1367 : * In which case both keys are given the same value(s). So you still have
1368 : * one "front" and one "back" value, only both are set to 123.
1369 : *
1370 : * If you want to have keys that include multiple names in themselves,
1371 : * use the period as in:
1372 : *
1373 : * \code
1374 : * --name:front.color red
1375 : * --name:back.color blue
1376 : * \endcode
1377 : *
1378 : * Internally, the period is a character like any other (and will remain
1379 : * that way) so the advgetopt library does not know that "front.color"
1380 : * would represent "color" field in the "front" object.
1381 : *
1382 : * \param[in] raw_key The key as written by the user.
1383 : *
1384 : * \return The canonicalized key or an empty string on error.
1385 : */
1386 0 : string_list_t getopt::parse_option_map(std::string const & raw_key)
1387 : {
1388 0 : string_list_t keys;
1389 0 : if(raw_key.empty())
1390 : {
1391 0 : return keys;
1392 : }
1393 :
1394 0 : if(raw_key[0] == '[')
1395 : {
1396 : // the array syntax allows for keys to be written between square
1397 : // brackets instead of separated by colon so [a][b][c] is equivalent
1398 : // to a:b:c
1399 : //
1400 0 : std::string result;
1401 0 : std::string::size_type pos(1);
1402 : for(;;)
1403 : {
1404 0 : std::string::size_type start(pos);
1405 0 : pos = raw_key.find(']', pos);
1406 0 : if(pos == std::string::npos)
1407 : {
1408 : // this is an error...
1409 : //
1410 0 : return string_list_t();
1411 : }
1412 0 : std::string key(raw_key.substr(start, pos - start));
1413 0 : if(!key.empty())
1414 : {
1415 0 : keys.push_back(key);
1416 : }
1417 0 : ++pos;
1418 0 : if(pos >= raw_key.length())
1419 : {
1420 0 : break;
1421 : }
1422 0 : if(raw_key[pos] != '[')
1423 : {
1424 : // the next key must start with a '['
1425 : //
1426 0 : return string_list_t();
1427 : }
1428 0 : ++pos;
1429 0 : }
1430 0 : }
1431 : else
1432 : {
1433 0 : split_string(raw_key, keys, {":"});
1434 : }
1435 :
1436 : // remove duplicates also sort the keys (which is not a perfect thing
1437 : // to do, but it shouldn't hurt except that numbers will not be sorted
1438 : // properly, i.e. "10" appears before "2").
1439 : //
1440 0 : std::sort(keys.begin(), keys.end());
1441 0 : keys.erase(std::unique(keys.begin(), keys.end()), keys.end());
1442 :
1443 0 : return keys;
1444 0 : }
1445 :
1446 :
1447 : /** \brief Return the alias if there is one.
1448 : *
1449 : * This function returns the input \p opt parameter unless it is an
1450 : * alias in which case the destination alias option is returned instead.
1451 : *
1452 : * \param[in] opt The option for which an alias is desired.
1453 : *
1454 : * \return \p opt unless it is an alias in which case
1455 : * opt->get_alias_destination() is returned.
1456 : *
1457 : * \sa option_info::get_alias()
1458 : */
1459 5380 : option_info::pointer_t getopt::get_alias_destination(option_info::pointer_t opt) const
1460 : {
1461 5380 : if(opt != nullptr
1462 5380 : && opt->has_flag(GETOPT_FLAG_ALIAS))
1463 : {
1464 95 : opt = opt->get_alias_destination();
1465 95 : if(opt == nullptr)
1466 : {
1467 1 : throw getopt_undefined("getopt::get_alias_destination(): alias is missing. Did you call link_aliases()?");
1468 : }
1469 : }
1470 :
1471 5379 : return opt;
1472 : }
1473 :
1474 :
1475 : /** \brief Retrieve the complete list of options.
1476 : *
1477 : * Applications that let their users enter dynamically options need to
1478 : * have access to the resulting list of options which may not otherwise
1479 : * be known.
1480 : *
1481 : * \return The map of options indexed by name.
1482 : *
1483 : * \sa parse_options_from_file()
1484 : */
1485 5 : option_info::map_by_name_t const & getopt::get_options() const
1486 : {
1487 5 : return f_options_by_name;
1488 : }
1489 :
1490 :
1491 : /** \brief Retrieve an option by name.
1492 : *
1493 : * This function retrieves an option by name. The function handles the
1494 : * special case of the default option. This means "--" can always be
1495 : * used to access the default option, whatever the name given to that
1496 : * option in the declaration of your options.
1497 : *
1498 : * Of course, if no default is defined, then "--" returns a nullptr.
1499 : *
1500 : * By default the function returns the final option. That is, if the
1501 : * named option is an alias, the destination option is returned, not
1502 : * the alias. This way the rest of the code is much simpler. You may
1503 : * get the exact option, even if it is aliased, by setting the
1504 : * \p exact_option parameter to true. It is really rare that you
1505 : * would need to do so.
1506 : *
1507 : * \note
1508 : * The \p name parameter could be an empty string to represent the default
1509 : * value (I think that's what that was for, now you use "--"). I've added
1510 : * the throw in this function to catch that invalid use, which either means
1511 : * you tried to check something with an invalid name or are expected to use
1512 : * the "--".
1513 : *
1514 : * \param[in] name The name of the option to retrieve.
1515 : * \param[in] exact_option Return the exact option, not its alias.
1516 : *
1517 : * \return The pointer to the named option or nullptr if not found.
1518 : */
1519 6815 : option_info::pointer_t getopt::get_option(std::string const & name, bool exact_option) const
1520 : {
1521 6815 : option_info::pointer_t opt;
1522 :
1523 6815 : if(name.empty())
1524 : {
1525 : // see \note section in doxy above about this
1526 : //
1527 4 : throw getopt_invalid_parameter("get_option() `name` argument cannot be empty.");
1528 : }
1529 :
1530 6811 : std::string const n(option_with_dashes(name));
1531 :
1532 : // we need this special case when looking for the default option
1533 : // because the name may not be "--" in the option table
1534 : // (i.e. you could call your default option "filenames" for example.)
1535 : //
1536 6811 : if(n.length() == 2
1537 504 : && n[0] == '-'
1538 7315 : && n[1] == '-')
1539 : {
1540 499 : opt = f_default_option;
1541 : }
1542 : else
1543 : {
1544 6312 : short_name_t short_name(string_to_short_name(n));
1545 6312 : if(short_name != NO_SHORT_NAME)
1546 : {
1547 6 : auto it(f_options_by_short_name.find(short_name));
1548 6 : if(it != f_options_by_short_name.end())
1549 : {
1550 2 : opt = it->second;
1551 : }
1552 : }
1553 : else
1554 : {
1555 6306 : auto it(f_options_by_name.find(n));
1556 6306 : if(it != f_options_by_name.end())
1557 : {
1558 3797 : opt = it->second;
1559 : }
1560 : }
1561 : }
1562 :
1563 : return exact_option
1564 : ? opt
1565 13622 : : get_alias_destination(opt);
1566 6816 : }
1567 :
1568 :
1569 : /** \brief Get an option using its short name.
1570 : *
1571 : * This function searches for an option given its short name.
1572 : *
1573 : * By default the function returns the final option. That is, if the
1574 : * named option is an alias, the destination option is returned, not
1575 : * the alias. This way the rest of the code is much simpler. You may
1576 : * get the exact option, even if it is aliased, by setting the
1577 : * \p exact_option parameter to true. It is really rare that you
1578 : * would need to do so, though.
1579 : *
1580 : * \param[in] short_name The short name of the option to look for.
1581 : * \param[in] exact_option Return the exact option, not its alias.
1582 : *
1583 : * \return The pointer to the option or nullptr if not found.
1584 : */
1585 2136 : option_info::pointer_t getopt::get_option(short_name_t short_name, bool exact_option) const
1586 : {
1587 2136 : auto it(f_options_by_short_name.find(short_name));
1588 2136 : if(it == f_options_by_short_name.end())
1589 : {
1590 1857 : return option_info::pointer_t();
1591 : }
1592 :
1593 : return exact_option
1594 8 : ? it->second
1595 287 : : get_alias_destination(it->second);
1596 : }
1597 :
1598 :
1599 : /** \brief Read parameters of the current option.
1600 : *
1601 : * This function saves the option in the list of options found in this list
1602 : * of arguments. If the option is expected to have parameters, then those
1603 : * are taken from the argv array before the function saves the option in
1604 : * the object list. The index, \p i, is increased accordingly.
1605 : *
1606 : * \warning
1607 : * This function cannot be called properly with the '-' option in case it
1608 : * is viewed as a default parameter. This is because the algorithm expects
1609 : * the index (\p i) to be pointing to the command line option and not the
1610 : * argument to that command.
1611 : *
1612 : * \param[in] opt The concerned option
1613 : * \param[in] i The current position, starting with the option position
1614 : * \param[in] argc The number of arguments in the argv array.
1615 : * \param[in] argv The list of argument strings.
1616 : * \param[in] option_keys An array of keys to prepend to each value.
1617 : * \param[in] source Where the value comes from.
1618 : */
1619 364 : void getopt::add_options(
1620 : option_info::pointer_t opt
1621 : , int & i
1622 : , int argc
1623 : , char ** argv
1624 : , string_list_t const & option_keys
1625 : , option_source_t source)
1626 : {
1627 364 : if(opt->has_flag(GETOPT_FLAG_FLAG))
1628 : {
1629 154 : opt->add_value(opt->get_default(), option_keys, source);
1630 : }
1631 : else
1632 : {
1633 210 : if(i + 1 < argc && !is_arg(argv[i + 1]))
1634 : {
1635 187 : if(opt->has_flag(GETOPT_FLAG_MULTIPLE))
1636 : {
1637 : do
1638 : {
1639 78 : ++i;
1640 78 : opt->add_value(argv[i], option_keys, source);
1641 : }
1642 78 : while(i + 1 < argc && !is_arg(argv[i + 1]));
1643 : }
1644 : else
1645 : {
1646 152 : ++i;
1647 152 : opt->add_value(argv[i], option_keys, source);
1648 : }
1649 : }
1650 : else
1651 : {
1652 23 : if(opt->has_flag(GETOPT_FLAG_REQUIRED))
1653 : {
1654 6 : cppthread::log << cppthread::log_level_t::error
1655 3 : << "option --"
1656 3 : << opt->get_name()
1657 3 : << " expects an argument."
1658 6 : << cppthread::end;
1659 : }
1660 : else
1661 : {
1662 : // We need to set something because the value is being
1663 : // set although no argument was specified (but that's
1664 : // legal by this argument's definition)
1665 : //
1666 20 : opt->add_value(std::string(), option_keys, source);
1667 : }
1668 : }
1669 : }
1670 364 : }
1671 :
1672 :
1673 : /** \brief Add an option with a value defined in a string.
1674 : *
1675 : * This function accepts a string as the value. If the option accepts
1676 : * multiple values, then the function makes use of the set_multiple_value()
1677 : * function of the option_info class. This will break the option up in
1678 : * multiple values if possible.
1679 : *
1680 : * \note
1681 : * The function doesn't verify that the \p opt parameter is indeed an
1682 : * option defined in this getopt object. It is your responsibility to
1683 : * not mix options from different getopt.
1684 : *
1685 : * \param[in] opt The option receiving a value.
1686 : * \param[in] value The value to assign this option.
1687 : * \param[in] filename The name of a configuration file if the option was
1688 : * read from such.
1689 : * \param[in] option_keys An array of keys to prepend to each value.
1690 : * \param[in] source Where the value comes from.
1691 : */
1692 115 : void getopt::add_option_from_string(
1693 : option_info::pointer_t opt
1694 : , std::string const & value
1695 : , std::string const & filename
1696 : , string_list_t const & option_keys
1697 : , option_source_t source)
1698 : {
1699 : // is the value defined?
1700 : //
1701 115 : if(!value.empty())
1702 : {
1703 111 : if(!opt->has_flag(GETOPT_FLAG_FLAG))
1704 : {
1705 : // does the option support multiple entries?
1706 : //
1707 107 : if(opt->has_flag(GETOPT_FLAG_MULTIPLE))
1708 : {
1709 23 : opt->set_multiple_values(value, option_keys, source);
1710 : }
1711 : else
1712 : {
1713 84 : opt->set_value(0, value, option_keys, source);
1714 : }
1715 107 : return;
1716 : }
1717 :
1718 : // for flags, allow "true" or "false" that way we can reset those
1719 : // flags and especially, it's possible to use them in configuration
1720 : // files that way
1721 : //
1722 4 : if(is_false(value))
1723 : {
1724 2 : opt->reset();
1725 2 : return;
1726 : }
1727 :
1728 2 : if(is_true(value))
1729 : {
1730 : // for this, pass an empty string to the next layer
1731 : //
1732 1 : opt->set_value(0, std::string(), option_keys, source);
1733 1 : return;
1734 : }
1735 :
1736 : #pragma GCC diagnostic push
1737 : #pragma GCC diagnostic ignored "-Wrestrict"
1738 2 : cppthread::log << cppthread::log_level_t::error
1739 1 : << "option "
1740 1 : << (filename.empty()
1741 3 : ? "--" + opt->get_name()
1742 3 : : "\"" + option_with_underscores(opt->get_name()) + "\"")
1743 1 : << " cannot be given value \""
1744 1 : << value
1745 1 : << "\""
1746 1 : << (filename.empty()
1747 3 : ? std::string()
1748 : : " in configuration file \""
1749 2 : + filename
1750 1 : + "\"")
1751 1 : << ". It only accepts \"true\" or \"false\"."
1752 4 : << cppthread::end;
1753 : #pragma GCC diagnostic pop
1754 1 : return;
1755 : }
1756 :
1757 : // does the option require a value when used?
1758 : //
1759 4 : if(opt->has_flag(GETOPT_FLAG_REQUIRED))
1760 : {
1761 : #pragma GCC diagnostic push
1762 : #pragma GCC diagnostic ignored "-Wrestrict"
1763 2 : cppthread::log << cppthread::log_level_t::error
1764 1 : << "option "
1765 1 : << (filename.empty()
1766 2 : ? "--" + opt->get_name()
1767 2 : : "\"" + option_with_underscores(opt->get_name()) + "\"")
1768 1 : << " must be given a value"
1769 1 : << (filename.empty()
1770 2 : ? std::string()
1771 : : " in configuration file \""
1772 1 : + filename
1773 1 : + "\"")
1774 1 : << "."
1775 4 : << cppthread::end;
1776 : #pragma GCC diagnostic pop
1777 1 : return;
1778 : }
1779 :
1780 : // accept an empty value otherwise
1781 : //
1782 3 : opt->set_value(0, value, option_keys, source);
1783 : }
1784 :
1785 :
1786 : /** \brief Retrieve a pointer to the variables defined in the getopt object.
1787 : *
1788 : * This function retrieves the variables defined in the getopt object.
1789 : * This is useful if you want to support those variables within
1790 : * configuration files that you read later on.
1791 : *
1792 : * \note
1793 : * This pointer is never a nullptr.
1794 : *
1795 : * \return A pointer to the getopt variables.
1796 : */
1797 1 : variables::pointer_t getopt::get_variables() const
1798 : {
1799 1 : return f_variables;
1800 : }
1801 :
1802 :
1803 :
1804 : } // namespace advgetopt
1805 : // vim: ts=4 sw=4 et
|