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