Line data Source code
1 : /*
2 : * License:
3 : * Copyright (c) 2006-2019 Made to Order Software Corp. All Rights Reserved
4 : *
5 : * https://snapwebsites.org/
6 : * contact@m2osw.com
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 2 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License along
19 : * with this program; if not, write to the Free Software Foundation, Inc.,
20 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 : *
22 : * Authors:
23 : * Alexis Wilke alexis@m2osw.com
24 : * Doug Barbieri doug@m2osw.com
25 : */
26 :
27 : /** \file
28 : * \brief Advanced getopt implementation.
29 : *
30 : * The advgetopt class and implementation is an advanced library to parse
31 : * command line parameters from static definitions specified by the caller.
32 : *
33 : * The class supports the command line options, options found in a default
34 : * configuration file or in a user defined configuration file.
35 : *
36 : * The class also includes support for displaying error messages and help
37 : * information about all the command line arguments.
38 : */
39 :
40 :
41 : /** \mainpage
42 : * The advanced getopt library to handle your command line tools seemlessly.
43 : *
44 : * The library offers an advanced way to parse command line arguments,
45 : * an environment variable, and configuration files in a seamless manner.
46 : * The advgetopt::getopt class is what is used everywhere for that purpose.
47 : *
48 : * The class can be used in a very restrictive mode, meaning that all
49 : * the parameters must clearly be defined by the application. It can also
50 : * be used in a dynamic way where the parameters are dynamically added
51 : * to the list of available options.
52 : *
53 : * The library supports multiple levels in your options. The simplest
54 : * is to use a scope operator like so:
55 : *
56 : * \code
57 : * level1::level2::level3::etc = 123
58 : * \endcode
59 : *
60 : * \note
61 : * The library understands the scope operator (::), the period (.), and
62 : * the slash (/) as level separator. So the following are equivalent.
63 : * Internally, all are changed to the scope operator (::).
64 : *
65 : * \code
66 : * level1::level2::level3::etc = 123
67 : * level1.level2.level3.etc = 123
68 : * level1/level2/level3/etc = 123
69 : * \endcode
70 : *
71 : * The labels in a .ini format (i.e. `[name]` defines sections) are viewed
72 : * as a first level. That name automatically get prepended to the parameters
73 : * appearing under them. Additional levels can be added by using the
74 : * scope operator, again.
75 : *
76 : * \code
77 : * [level1]
78 : * level2::level3::etc = 123
79 : * \endcode
80 : *
81 : * Support for other formats may be added later. For example, we could
82 : * read XML and JSON files. Right now, we are focused on Unix configuration
83 : * files and pretty much never even need two levels.
84 : *
85 : * The library is capable of writing your configuration back to file. It
86 : * will know when a value was modified and only the modified values get
87 : * saved to the read/write configuration file(s). (Either the user file
88 : * or the system file under the `\<proc>.d/...` sub-path.)
89 : */
90 :
91 : // self
92 : //
93 : #include "advgetopt/advgetopt.h"
94 :
95 :
96 : // advgetopt lib
97 : //
98 : #include "advgetopt/exception.h"
99 :
100 :
101 : // cppthread lib
102 : //
103 : #include <cppthread/log.h>
104 :
105 :
106 : // libutf8 lib
107 : //
108 : #include <libutf8/iterator.h>
109 :
110 :
111 : // boost lib
112 : //
113 : #include <boost/algorithm/string/replace.hpp>
114 :
115 :
116 : // last include
117 : //
118 : #include <snapdev/poison.h>
119 :
120 :
121 :
122 :
123 :
124 : /** \brief The advgetopt environment to parse command line options.
125 : *
126 : * This namespace encompasses all the declarations and implementations
127 : * of functions used to parse and access the command line options.
128 : */
129 : namespace advgetopt
130 : {
131 :
132 :
133 : namespace
134 : {
135 :
136 :
137 : /** \brief Definitions of the system options.
138 : *
139 : * The system options are options we add automatically (if the user asked
140 : * for them) and handle automatically when they are found.
141 : *
142 : * The following are the currently supported system options:
143 : *
144 : * \li `--help`
145 : *
146 : * Print out the usage() with most of the command line arguments.
147 : *
148 : * \li '--long-help'
149 : *
150 : * Print all the command line arguments with usage().
151 : *
152 : * The long help is is only added if the list of options include at least
153 : * one group flag (GETOPT_FLAG_SHOW_GROUP1 or GETOPT_FLAG_SHOW_GROUP2).
154 : *
155 : * \li '--\<name>-help'
156 : *
157 : * Print the help from the group named \<name>.
158 : *
159 : * These command line options are added only when groups are defined.
160 : *
161 : * \li `--version`
162 : *
163 : * Print out the version.
164 : *
165 : * \li `--copyright`
166 : *
167 : * Print out the copyright notice.
168 : *
169 : * \li `--license`
170 : *
171 : * Print out the license notice.
172 : *
173 : * \li `--build-date`
174 : *
175 : * Print out the build time and date.
176 : *
177 : * \li `--environment-variable-name`
178 : *
179 : * Print out the build time and date.
180 : *
181 : * \li `--configuration-filenames`
182 : *
183 : * Print out the list of configuration file names that the system checks
184 : * for configuration data.
185 : *
186 : * \li `--path-to-option-definitions`
187 : *
188 : * Print out the path to files which define options for this tool.
189 : */
190 : option const g_system_options[] =
191 : {
192 : define_option(
193 : Name("help")
194 : , ShortName('h')
195 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS
196 : , GETOPT_FLAG_SHOW_USAGE_ON_ERROR>())
197 : , Help("print out this help screen and exit.")
198 : ),
199 : define_option(
200 : Name("version")
201 : , ShortName('V')
202 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
203 : , Help("print out the version of %p and exit.")
204 : ),
205 : define_option(
206 : Name("copyright")
207 : , ShortName('C')
208 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
209 : , Help("print out the copyright of %p and exit.")
210 : ),
211 : define_option(
212 : Name("license")
213 : , ShortName('L')
214 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
215 : , Help("print out the license of %p and exit.")
216 : ),
217 : define_option(
218 : Name("build-date")
219 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
220 : , Help("print out the time and date when %p was built and exit.")
221 : ),
222 : define_option(
223 : Name("environment-variable-name")
224 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
225 : , Help("print out the name of the environment variable supported by %p (if any.)")
226 : ),
227 : define_option(
228 : Name("configuration-filenames")
229 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
230 : , Help("print out the list of configuration files checked out by this tool.")
231 : ),
232 : define_option(
233 : Name("path-to-option-definitions")
234 : , Flags(standalone_command_flags<GETOPT_FLAG_GROUP_COMMANDS>())
235 : , Help("print out the path to the option definitons.")
236 : ),
237 : end_options()
238 : };
239 :
240 :
241 : /** \brief Optional list of options.
242 : *
243 : * This optional list of options is added only when the
244 : * f_configuration_filename parameter has a valid filename.
245 : *
246 : * The following are the currently added options:
247 : *
248 : * \li `--config-dir`
249 : *
250 : * This option allows for adding more configuration directories.
251 : * These work the same way as directories defined in the
252 : * f_configuration_directories.
253 : */
254 : option const g_if_configuration_filename_system_options[] =
255 : {
256 : define_option(
257 : Name("config-dir")
258 : , Flags(any_flags<GETOPT_FLAG_COMMAND_LINE
259 : , GETOPT_FLAG_ENVIRONMENT_VARIABLE
260 : , GETOPT_FLAG_REQUIRED
261 : , GETOPT_FLAG_MULTIPLE
262 : , GETOPT_FLAG_GROUP_OPTIONS>())
263 : , Help("add one or more configuration directory paths to search for configuration files.")
264 : ),
265 : end_options()
266 : };
267 :
268 :
269 :
270 :
271 : /** \brief Value when no default option was defined.
272 : *
273 : * Some options may have defaults in which case their indexes are used.
274 : * By default, an option has no defaults and we instead use -1.
275 : */
276 : int const NO_DEFAULT_OPT = -1;
277 :
278 :
279 : /** \brief Check whether this parameter is an argument.
280 : *
281 : * An argument is defined as a command line parameter that starts with
282 : * a dash and is not just "-".
283 : *
284 : * Note that "--" is viewed as an argument (this function returns true)
285 : * and the getopt class takes it as a command meaning any other parameter
286 : * is not an argument.
287 : */
288 215 : bool is_arg(char const * a)
289 : {
290 : // "-" and "--" are not options; however "--" returns true
291 : // because after a "--" we take the data as default arguments
292 215 : return a[0] == '-' && a[1] != '\0';
293 : }
294 :
295 : } // no name namespace
296 :
297 :
298 :
299 : /** \class getopt_exception
300 : * \brief Base exception of the advgetopt class.
301 : *
302 : * This exception is the base exception of all the advgetopt exceptions.
303 : * Catching this exception allows you to capture all the getopt exceptions.
304 : */
305 :
306 :
307 : /** \class getopt_exception_default
308 : * \brief No default and no value specified.
309 : *
310 : * When a parameter is not specified and no default is available, this
311 : * exception is raised.
312 : */
313 :
314 :
315 : /** \class getopt_exception_undefined
316 : * \brief Attempting to access something that is undefined.
317 : *
318 : * This exception is used when you attempt to access data that was not
319 : * defined. For example, if your tool tries to read parameter "version"
320 : * and that was not defined in the list of options, this exception is
321 : * raised.
322 : */
323 :
324 :
325 : /** \class getopt_exception_invalid
326 : * \brief Attempted to use some invalid data.
327 : *
328 : * This exception is used whenever an attempt is made to access data that
329 : * does not make sense (is invalid.)
330 : *
331 : * For example, the table of options makes use of enumerations for different
332 : * parts. If one of these has a value which does not represent a valid
333 : * enumeration value, then this exception is raised.
334 : */
335 :
336 :
337 : /** \class getopt
338 : * \brief Class used to parse command line options.
339 : *
340 : * This class is the one used by all the wpkg tools to parse the command line
341 : * options. It is very advanced and is capable to read many different types
342 : * of options with a letter (-h) and a word (--verbose) with no parameters,
343 : * one parameter, any number of parameters, and a set of "filenames" (lose
344 : * options that are not specific to an option.)
345 : */
346 :
347 :
348 : /** \struct option
349 : * \brief Structure representing an option.
350 : *
351 : * When creating a getopt() object you have to pass an array of options. That
352 : * array is defined as a set of option structures where the last one has
353 : * its f_arg_mode set to end_of_options. The other parameters may still be
354 : * defined as the last option is used to define what the parser should do
355 : * with the lose options (in most cases it is named "filenames" and used
356 : * as an array of files, paths, windows package names, etc.)
357 : */
358 :
359 :
360 : /** \brief Initialize the getopt object.
361 : *
362 : * \section into Introduction
363 : *
364 : * This constructor initializes a getopt object. It also reads and parses
365 : * the corresponding option configuration file if it exists (based on the
366 : * project name defined in the environment parameter.)
367 : *
368 : * \section program_name Program Name
369 : *
370 : * Once constructed, if you want to have access to the program name, make
371 : * sure to call this function with your `argv` variable:
372 : *
373 : * \code
374 : * opt.parse_program_name(argv);
375 : * \endcode
376 : *
377 : * Remember that the program name is often used in error messages so having
378 : * it defined early is generally a good idea.
379 : *
380 : * \section dynamism Dynamic Options
381 : *
382 : * This constructor is most often used when you want to dynamically add
383 : * options to your executable with the parse_options_info() function.
384 : * For example, the list of options may vary slightly depending on what
385 : * your command is named when launched.
386 : *
387 : * For example:
388 : *
389 : * \code
390 : * if(time(nullptr) & 1)
391 : * {
392 : * opt.parse_options_info(odd_options);
393 : * }
394 : * else
395 : * {
396 : * opt.parse_options_info(even_options);
397 : * }
398 : * \endcode
399 : *
400 : * \section aliases Linking Aliases
401 : *
402 : * After you added all your dynamic options, you want to make sure that
403 : * aliases are linked to the final option. You should always call that
404 : * function because you can't be sure whether someone will add such an
405 : * alias in the .ini option file.
406 : *
407 : * \code
408 : * opt.link_aliases();
409 : * \endcode
410 : *
411 : * You can call this function any number of times. So if you add yet
412 : * more dynamic options at a later time, just make sure to call it
413 : * again in case aliases were added.
414 : *
415 : * \section parse Parse the Arguments
416 : *
417 : * Finally, you want to call the following functions in that order to
418 : * parse the data from configuration files, the environment variable,
419 : * and the list of command line arguments:
420 : *
421 : * \code
422 : * opt.parse_configuration_files();
423 : * opt.parse_environment_variable();
424 : * opt.parse_arguments(argc, argv);
425 : * \endcode
426 : *
427 : * The order is important because the last command line option found is
428 : * the one kept. So if the same argument is found in the configuration
429 : * file, the environment variable and the command line, the one on the
430 : * command line is kept. In most cases it makes no difference for standalone
431 : * flags, but arguments that expect a parameter will be changed to the last
432 : * specified value.
433 : *
434 : * If you want to determine the configuration filenames, you may use the
435 : * process_configuration_file() function directly instead of the
436 : * parse_configuration_files() function. This also gives you the ability
437 : * to test whether a configuration file was indeed read.
438 : *
439 : * Note that the parse_arguments() last parameter (only_environment_variable)
440 : * is expected to be left along when you call it with `argc` and `argv`.
441 : *
442 : * If you just have a string instead of an `argv` variable, call the
443 : * parse_string() function instead. It will transform your string in an
444 : * array of arguments and then call the parse_arguments() for you.
445 : *
446 : * \attention
447 : * Note that the program name does not get defined until you call the
448 : * parse_program_name() function since that information comes from the
449 : * first arguments of your command line which we do not get on
450 : * construction in this case.
451 : *
452 : * \attention
453 : * Since the arguments are not known to the getopt system yet, the
454 : * GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS is not used in
455 : * this case.
456 : *
457 : * \param[in] opt_env The list of options that your program supports.
458 : *
459 : * \sa link_aliases()
460 : * \sa parse_arguments()
461 : * \sa parse_configuration_files()
462 : * \sa parse_environment_variable()
463 : * \sa parse_string()
464 : * \sa process_configuration_file()
465 : *
466 : * \sa initialize_parser()
467 : * \sa finish_parsing()
468 : */
469 76 : getopt::getopt(options_environment const & opt_env)
470 : {
471 76 : initialize_parser(opt_env);
472 76 : }
473 :
474 :
475 : /** \brief Initialize the getopt object.
476 : *
477 : * The constructor initializes a getopt object and parse the specified
478 : * argv array. If defined, it also parses a configuration file and
479 : * an environment variable.
480 : *
481 : * The order in which parameters are parsed is important since only the
482 : * last value is kept:
483 : *
484 : * \li Each existing configuration file in the order defined in the vector;
485 : * \li The environment variable;
486 : * \li the argv array.
487 : *
488 : * The constructor calls the reset() function to start the parsing. It is
489 : * possible to call the reset() function at any time to parse a new set
490 : * of parameters.
491 : *
492 : * The argv array cannot be nullptr and the array cannot be empty. It must have
493 : * at least one entry representing the program name (argv[0]).
494 : *
495 : * The configuration_files vector can be empty in which case no configuration
496 : * files are read.
497 : *
498 : * The environment_variable_name can be nullptr or the empty string in which case
499 : * it is ignored.
500 : *
501 : * \note
502 : * All the data gets copied while parsed. If the argv array is deleted on
503 : * return, the getopt object remains valid.
504 : *
505 : * \exception getopt_exit
506 : * This function calls finish_parsing() which may throw this exception.
507 : * See that function for details.
508 : *
509 : * \param[in] opt_env The list of options that your program supports.
510 : * \param[in] argc The number of arguments in argv.
511 : * \param[in] argv An array of strings representing arguments.
512 : *
513 : * \sa initialize_parser()
514 : * \sa finish_parsing()
515 : */
516 257 : getopt::getopt(options_environment const & opt_env
517 : , int argc
518 280 : , char * argv[])
519 : {
520 257 : initialize_parser(opt_env);
521 246 : finish_parsing(argc, argv);
522 234 : }
523 :
524 :
525 : /** \brief Initialize the parser.
526 : *
527 : * This function is called from the two constructors. It initializes the
528 : * basic options from the user definitions, the file when there is one,
529 : * the group names, and if allowed the system command line options.
530 : *
531 : * This is enough to then parse arguments or configuration files, although
532 : * in most cases this is used to allow for additional environment options
533 : * to be inserted before calling the finish_parsing() function.
534 : *
535 : * \param[in] opt_env The list of options that your program supports.
536 : */
537 333 : void getopt::initialize_parser(options_environment const & opt_env)
538 : {
539 333 : f_options_environment = opt_env;
540 :
541 333 : parse_options_info(f_options_environment.f_options, false);
542 325 : parse_options_from_file();
543 322 : parse_options_from_group_names();
544 322 : if(has_flag(GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS | GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS))
545 : {
546 73 : parse_options_info(g_system_options, true);
547 73 : if(f_options_environment.f_configuration_filename != nullptr
548 16 : && *f_options_environment.f_configuration_filename != '\0')
549 : {
550 13 : parse_options_info(g_if_configuration_filename_system_options, true);
551 : }
552 : }
553 322 : }
554 :
555 :
556 : /** \brief Actually parse everything.
557 : *
558 : * This function allows you to run the second half of the initialization
559 : * process. We've broken this process up in two, so you can initialize
560 : * a getopt object, add some other options, then finish up the
561 : * initialization process by calling this function.
562 : *
563 : * The command line arguments, configuration files.
564 : *
565 : * \exception getopt_exit
566 : * If the GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS is set and
567 : * a system command was specified on the command, such as --help or
568 : * --version, then that command is run and the function throws this
569 : * exception.
570 : *
571 : * \param[in] argc The number of arguments in argv.
572 : * \param[in] argv An array of strings representing arguments.
573 : */
574 246 : void getopt::finish_parsing(int argc, char * argv[])
575 : {
576 246 : if(argv == nullptr)
577 : {
578 1 : throw getopt_logic_error("argv pointer cannot be nullptr");
579 : }
580 :
581 245 : parse_program_name(argv);
582 245 : if(f_options_by_name.empty())
583 : {
584 3 : throw getopt_logic_error("an empty list of options is not legal, you must defined at least one (i.e. --version, --help...)");
585 : }
586 :
587 242 : link_aliases();
588 :
589 238 : parse_configuration_files();
590 238 : parse_environment_variable();
591 238 : parse_arguments(argc, argv, false);
592 :
593 238 : if(has_flag(GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS))
594 : {
595 5 : flag_t const result(process_system_options(std::cout));
596 5 : if((result & SYSTEM_OPTION_COMMANDS_MASK) != 0)
597 : {
598 4 : throw getopt_exit("system command processed.", 0);
599 : }
600 : }
601 234 : }
602 :
603 :
604 : /** \brief Return a reference to the options environment.
605 : *
606 : * This function returns a reference to the options environment that
607 : * was passed to the constructor. This is useful to functions that
608 : * do not otherwise have access to that object.
609 : *
610 : * \return This getopt options environment.
611 : */
612 1 : options_environment const & getopt::get_options_environment() const
613 : {
614 1 : return f_options_environment;
615 : }
616 :
617 :
618 : /** \brief Check whether an environment flag is set or not.
619 : *
620 : * This function checks the environment flags for the specified \p flag.
621 : * When the flag is set, the function returns true.
622 : *
623 : * You may test multiple flags at the same time, if any one of them is set,
624 : * then the function returns true.
625 : *
626 : * \param[in] flag The flag to check out.
627 : *
628 : * \return true if the flag is set.
629 : */
630 723 : bool getopt::has_flag(flag_t flag) const
631 : {
632 723 : return (f_options_environment.f_environment_flags & flag) != 0;
633 : }
634 :
635 :
636 : /** \brief Check for an environment variable.
637 : *
638 : * If the name of an environment variable is specified in the option
639 : * environment structure, then it is read as a command line string.
640 : * This function parses the string in an array of strings and then parses
641 : * it as an argv array (just like the argv parameter defined in a main()
642 : * function).
643 : *
644 : * Since the environment variable is checked after the configuration files,
645 : * the options defined in the variable can change the definitions from
646 : * the configuration files.
647 : *
648 : * Like in the configuration files, only options can be specified in the
649 : * environment variable and commands generate an error. The system knows
650 : * since options that can be included in the environment variable are
651 : * marked by the GETOPT_FLAG_ENVIRONMENT_VARIABLE flag. In other words,
652 : * you may allow options to appear on the command line, in configuration
653 : * files, in environment variables or a mix of all of these locations.
654 : */
655 245 : void getopt::parse_environment_variable()
656 : {
657 245 : if(f_options_environment.f_environment_variable_name == nullptr
658 120 : || *f_options_environment.f_environment_variable_name == '\0')
659 : {
660 : // no name
661 : //
662 130 : return;
663 : }
664 :
665 115 : char const * s(getenv(f_options_environment.f_environment_variable_name));
666 115 : if(s == nullptr)
667 : {
668 : // no environment variable with that name
669 : //
670 65 : return;
671 : }
672 :
673 50 : parse_string(s, true);
674 : }
675 :
676 :
677 : /** \brief Parse a string similar to a command line argument.
678 : *
679 : * This function parses a line of command line argument from a string.
680 : * Especially, it is used to parse the environment variable which is
681 : * a string of arguments.
682 : *
683 : * This can be used to parse the command line string as received under
684 : * MS-Windows (i.e. an unparsed one long string of arguments, where
685 : * you also need to do the glob() calls.)
686 : *
687 : * This function actually transforms the input string in an array of
688 : * strings and then calls the parse_arguments() function.
689 : *
690 : * \note
691 : * The input allows for an empty string in which case pretty much nothing
692 : * happens.
693 : *
694 : * \param[in] str The string that is going to be parsed.
695 : * \param[in] only_environment_variable Whether only options marked with
696 : * the GETOPT_FLAG_ENVIRONMENT_VARIABLE flag are accepted.
697 : */
698 50 : void getopt::parse_string(std::string const & str, bool only_environment_variable)
699 : {
700 : // this is exactly like the command line only in an environment variable
701 : // so parse the parameters just like the shell
702 : //
703 98 : string_list_t args;
704 98 : std::string a;
705 50 : char const * s(str.c_str());
706 2968 : while(*s != '\0')
707 : {
708 1459 : if(isspace(*s))
709 : {
710 130 : if(!a.empty())
711 : {
712 128 : args.push_back(a);
713 128 : a.clear();
714 : }
715 1 : do
716 : {
717 131 : ++s;
718 : }
719 131 : while(isspace(*s));
720 : }
721 1329 : else if(*s == '"'
722 1328 : || *s == '\'')
723 : {
724 : // support quotations and remove them from the argument
725 3 : char const quote(*s++);
726 85 : while(*s != '\0'
727 44 : && *s != quote)
728 : {
729 41 : a += *s++;
730 : }
731 3 : if(*s != '\0')
732 : {
733 3 : ++s;
734 3 : }
735 : }
736 : else
737 : {
738 1326 : a += *s++;
739 : }
740 : }
741 :
742 50 : if(!a.empty())
743 : {
744 46 : args.push_back(a);
745 : }
746 :
747 50 : if(args.empty())
748 : {
749 : // nothing extra to do
750 : //
751 2 : return;
752 : }
753 :
754 : // TODO: expand the arguments that include unquoted '*', '?', '[...]'
755 : // (note that we remove the quoates at the moment so we'd have
756 : // to keep track of that specific problem...)
757 :
758 : // the argv array has to be a null terminated bare string pointers
759 : //
760 96 : std::vector<char *> sub_argv;
761 :
762 48 : sub_argv.resize(args.size() + 2);
763 :
764 : // argv[0] is the program name
765 : //
766 48 : sub_argv[0] = const_cast<char *>(f_program_fullname.c_str());
767 :
768 : // the other arguments are from the variable
769 : //
770 222 : for(size_t idx(0); idx < args.size(); ++idx)
771 : {
772 174 : sub_argv[idx + 1] = const_cast<char *>(args[idx].c_str());
773 : }
774 :
775 : // this is probably already a nullptr
776 : //
777 48 : sub_argv[args.size() + 1] = nullptr;
778 :
779 : // now convert those parameters in values
780 : //
781 48 : parse_arguments(static_cast<int>(args.size() + 1), &sub_argv[0], only_environment_variable);
782 : }
783 :
784 :
785 : /** \brief Parse an array of arguments.
786 : *
787 : * This function accepts an array of arguments as received by the main()
788 : * function. By default, though, you pass the argc/argv parameters to
789 : * the getopt() constructor which automatically calls this function.
790 : *
791 : * This functin is public so you can call it with additional lists of
792 : * arguments. If that list of arguments comes as a string, you may want
793 : * to call the parse_string() function instead. It will transform your
794 : * string in a list of parameters for you.
795 : *
796 : * When the \p only_environment_variable parameter is set to true, then
797 : * it is considered that the input arguments were found in an environment
798 : * variables and they are only accepted if the corresponding option
799 : * definition includes the GETOPT_FLAG_ENVIRONMENT_VARIABLE flag.
800 : *
801 : * When the \p only_environment_variable parameter is set to false, the
802 : * arguments are viewed as command line arguments and the corresponding
803 : * options must include the GETOPT_FLAG_COMMAND_LINE flag.
804 : *
805 : * Variables get overridden by the newest values found in the list of
806 : * arguments.
807 : *
808 : * Note that the command line arguments are the only ones that should
809 : * include a command (opposed to an option that alters the behavior of
810 : * your commands.) However, the advgetopt system expects you to properly
811 : * define what can be used in a configuration file, in an environment
812 : * variable, or directly on the command line. It is not in charge of
813 : * that part in itself.
814 : *
815 : * \note
816 : * The code may find some errors in the tables passed to the advgetopt
817 : * environment (i.e. a duplicate definition.) When such errors are
818 : * detected, an exception is raised. Errors found on the command line
819 : * generate a log message. If you setup a callback, you can then decide
820 : * to either call exit(1) or raise your own exception.
821 : *
822 : * \note
823 : * The function does NOT check whether the list of arguments (argv) is
824 : * terminated by nullptr. The argc parameter must be correct.
825 : *
826 : * \param[in] argc The number of arguments in argv.
827 : * \param[in] argv The argument strings terminated by a nullptr.
828 : * \param[in] only_environment_variable Accept command line arguments (false)
829 : * or environment variable arguments (true).
830 : */
831 300 : void getopt::parse_arguments(int argc
832 : , char * argv[]
833 : , bool only_environment_variable)
834 : {
835 688 : for(int i(1); i < argc; ++i)
836 : {
837 403 : if(argv[i][0] == '-')
838 : {
839 348 : if(argv[i][1] == '-')
840 : {
841 298 : if(argv[i][2] == '\0')
842 : {
843 : // end of options, skip the '--' and then anything else
844 : // is taken as "filenames" (or whatever the tool expects)
845 : //
846 12 : if(f_default_option == nullptr)
847 : {
848 2 : cppthread::log << cppthread::log_level_t::error
849 1 : << "no default options defined; thus -- is not accepted by this program."
850 1 : << cppthread::end;
851 1 : break;
852 : }
853 :
854 11 : if(only_environment_variable)
855 : {
856 6 : if(!f_default_option->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
857 : {
858 2 : cppthread::log << cppthread::log_level_t::error
859 1 : << "option -- is not supported in the environment variable."
860 1 : << cppthread::end;
861 1 : break;
862 : }
863 : }
864 : else
865 : {
866 5 : if(!f_default_option->has_flag(GETOPT_FLAG_COMMAND_LINE))
867 : {
868 2 : cppthread::log << cppthread::log_level_t::error
869 1 : << "option -- is not supported in the environment variable."
870 1 : << cppthread::end;
871 1 : break;
872 : }
873 : }
874 :
875 : // in this case we do NOT test whether an argument uses
876 : // a dash (-) we take them all as default options
877 : //
878 37 : while(i + 1 < argc)
879 : {
880 14 : ++i;
881 14 : f_default_option->add_value(argv[i]);
882 : }
883 : }
884 : else
885 : {
886 : // a long option, check that it is defined in the
887 : // programmer defined options
888 : //
889 568 : std::string option_name(argv[i] + 2);
890 568 : std::string option_value;
891 286 : std::string::size_type const pos(option_name.find('='));
892 286 : if(pos != std::string::npos)
893 : {
894 11 : if(pos == 0)
895 : {
896 2 : cppthread::log << cppthread::log_level_t::error
897 1 : << "name missing in \""
898 1 : << argv[i]
899 1 : << "\"."
900 1 : << cppthread::end;
901 1 : break;
902 : }
903 :
904 10 : option_value = option_name.substr(pos + 1);
905 10 : option_name.resize(pos);
906 : }
907 566 : option_info::pointer_t opt(get_option(option_name));
908 284 : if(opt == nullptr)
909 : {
910 2 : cppthread::log << cppthread::log_level_t::error
911 1 : << "option --"
912 1 : << option_name
913 1 : << " is not supported."
914 1 : << cppthread::end;
915 1 : break;
916 : }
917 283 : if(only_environment_variable)
918 : {
919 47 : if(!opt->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
920 : {
921 2 : cppthread::log << cppthread::log_level_t::error
922 1 : << "option --"
923 1 : << option_name
924 1 : << " is not supported in the environment variable."
925 1 : << cppthread::end;
926 1 : break;
927 : }
928 : }
929 : else
930 : {
931 236 : if(!opt->has_flag(GETOPT_FLAG_COMMAND_LINE))
932 : {
933 2 : cppthread::log << cppthread::log_level_t::error
934 1 : << "option --"
935 1 : << option_name
936 1 : << " is not supported on the command line."
937 1 : << cppthread::end;
938 1 : break;
939 : }
940 : }
941 281 : if(pos != std::string::npos)
942 : {
943 : // the user specified a value after an equal sign
944 : //
945 8 : add_option_from_string(opt, option_value, std::string());
946 : }
947 : else
948 : {
949 273 : add_options(opt, i, argc, argv);
950 : }
951 : }
952 : }
953 : else
954 : {
955 50 : if(argv[i][1] == '\0')
956 : {
957 : // stdin/stdout (a '-' by itself)
958 : //
959 9 : if(f_default_option == nullptr)
960 : {
961 2 : cppthread::log << cppthread::log_level_t::error
962 1 : << "no default options defined; thus - is not accepted by this program."
963 1 : << cppthread::end;
964 1 : break;
965 : }
966 8 : if(only_environment_variable)
967 : {
968 4 : if(!f_default_option->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
969 : {
970 2 : cppthread::log << cppthread::log_level_t::error
971 1 : << "option - is not supported in the environment variable."
972 1 : << cppthread::end;
973 1 : break;
974 : }
975 : }
976 : else
977 : {
978 4 : if(!f_default_option->has_flag(GETOPT_FLAG_COMMAND_LINE))
979 : {
980 2 : cppthread::log << cppthread::log_level_t::error
981 1 : << "option - is not supported in the environment variable."
982 1 : << cppthread::end;
983 1 : break;
984 : }
985 : }
986 :
987 : // this is similar to a default option by itself
988 : //
989 6 : f_default_option->add_value(argv[i]);
990 : }
991 : else
992 : {
993 : // short option(s)
994 : //
995 : // i gets incremented by add_options() so we have to
996 : // keep a copy in `k`
997 : //
998 82 : std::string const short_args_string(argv[i] + 1);
999 81 : for(libutf8::utf8_iterator short_args(short_args_string)
1000 81 : ; short_args != short_args_string.end()
1001 : ; ++short_args)
1002 : {
1003 83 : option_info::pointer_t opt(get_option(*short_args));
1004 43 : if(opt == nullptr)
1005 : {
1006 2 : cppthread::log << cppthread::log_level_t::error
1007 1 : << "option -"
1008 2 : << short_name_to_string(*short_args)
1009 1 : << " is not supported."
1010 1 : << cppthread::end;
1011 1 : break;
1012 : }
1013 42 : if(only_environment_variable)
1014 : {
1015 17 : if(!opt->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1016 : {
1017 2 : cppthread::log << cppthread::log_level_t::error
1018 1 : << "option -"
1019 2 : << short_name_to_string(*short_args)
1020 1 : << " is not supported in the environment variable."
1021 1 : << cppthread::end;
1022 1 : break;
1023 : }
1024 : }
1025 : else
1026 : {
1027 25 : if(!opt->has_flag(GETOPT_FLAG_COMMAND_LINE))
1028 : {
1029 2 : cppthread::log << cppthread::log_level_t::error
1030 1 : << "option -"
1031 2 : << short_name_to_string(*short_args)
1032 1 : << " is not supported on the command line."
1033 1 : << cppthread::end;
1034 1 : break;
1035 : }
1036 : }
1037 40 : add_options(opt, i, argc, argv);
1038 : }
1039 : }
1040 : }
1041 : }
1042 : else
1043 : {
1044 : // direct entry (filename or whatever the tool expects as a default)
1045 : //
1046 55 : if(f_default_option == nullptr)
1047 : {
1048 4 : cppthread::log << cppthread::log_level_t::error
1049 2 : << "no default options defined; we do not know what to do of \""
1050 2 : << argv[i]
1051 2 : << "\"; standalone parameters are not accepted by this program."
1052 2 : << cppthread::end;
1053 2 : break;
1054 : }
1055 53 : if(only_environment_variable)
1056 : {
1057 27 : if(!f_default_option->has_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE))
1058 : {
1059 2 : cppthread::log << cppthread::log_level_t::error
1060 1 : << "default options are not supported in the environment variable."
1061 1 : << cppthread::end;
1062 1 : break;
1063 : }
1064 : }
1065 : else
1066 : {
1067 26 : if(!f_default_option->has_flag(GETOPT_FLAG_COMMAND_LINE))
1068 : {
1069 2 : cppthread::log << cppthread::log_level_t::error
1070 1 : << "default options are not supported on the command line."
1071 1 : << cppthread::end;
1072 1 : break;
1073 : }
1074 : }
1075 51 : f_default_option->add_value(argv[i]);
1076 : }
1077 : }
1078 299 : }
1079 :
1080 :
1081 : /** \brief Return the alias if there is one.
1082 : *
1083 : * This function returns the input \p opt parameter unless it is an
1084 : * alias in which case the destination alias option is returned instead.
1085 : *
1086 : * \param[in] opt The option for which an alias is desired.
1087 : *
1088 : * \return \p opt unless it is an alias in which case
1089 : * opt->get_alias_destination() is returned.
1090 : *
1091 : * \sa option_info::get_alias()
1092 : */
1093 4600 : option_info::pointer_t getopt::get_alias_destination(option_info::pointer_t opt) const
1094 : {
1095 9200 : if(opt != nullptr
1096 4600 : && opt->has_flag(GETOPT_FLAG_ALIAS))
1097 : {
1098 90 : opt = opt->get_alias_destination();
1099 90 : if(opt == nullptr)
1100 : {
1101 1 : throw getopt_undefined("getopt::get_alias_destination(): alias is missing. Did you call link_aliases()?");
1102 : }
1103 : }
1104 :
1105 4599 : return opt;
1106 : }
1107 :
1108 :
1109 : /** \brief Retrieve the complete list of options.
1110 : *
1111 : * Applications that let their users enter dynamically options need to
1112 : * have access to the resulting list of options which may not otherwise
1113 : * be known.
1114 : *
1115 : * \return The map of options indexed by name.
1116 : *
1117 : * \sa parse_options_from_file()
1118 : */
1119 1 : option_info::map_by_name_t const & getopt::get_options() const
1120 : {
1121 1 : return f_options_by_name;
1122 : }
1123 :
1124 :
1125 : /** \brief Retrieve an option by name.
1126 : *
1127 : * This function retrieves an option by name. The function handles the
1128 : * special case of the default option. This means "--" can always be
1129 : * used to access the default option, whever the name given to that
1130 : * option in the declaration of your options.
1131 : *
1132 : * Of course, if no default is defined, then "--" returns a nullptr.
1133 : *
1134 : * By default the function returns the final option. That is, if the
1135 : * named option is an alias, the destination option is returned, not
1136 : * the alias. This way the rest of the code is much simpler. You may
1137 : * get the exact option, even if it is aliased, by setting the
1138 : * \p exact_option parameter to true. It is really rare that you
1139 : * would need to do so, though.
1140 : *
1141 : * \param[in] name The name of the option to retrieve.
1142 : * \param[in] exact_option Return the exact option, not its alias.
1143 : *
1144 : * \return The pointer to the named option or nullptr if not found.
1145 : */
1146 5383 : option_info::pointer_t getopt::get_option(std::string const & name, bool exact_option) const
1147 : {
1148 : // we need a special case when looking for the default option
1149 : // because the name may not be "--" in the option table
1150 : // (i.e. you could call your default option "filenames" for
1151 : // example.)
1152 : //
1153 10766 : option_info::pointer_t opt;
1154 :
1155 10766 : std::string const n(boost::replace_all_copy(name, "_", "-"));
1156 :
1157 10766 : if(n.length() == 2
1158 459 : && n[0] == '-'
1159 5837 : && n[1] == '-')
1160 : {
1161 454 : opt = f_default_option;
1162 : }
1163 : else
1164 : {
1165 4929 : short_name_t short_name(string_to_short_name(n));
1166 4929 : if(short_name != NO_SHORT_NAME)
1167 : {
1168 6 : auto it(f_options_by_short_name.find(short_name));
1169 6 : if(it != f_options_by_short_name.end())
1170 : {
1171 2 : opt = it->second;
1172 : }
1173 : }
1174 : else
1175 : {
1176 4923 : auto it(f_options_by_name.find(n));
1177 4923 : if(it != f_options_by_name.end())
1178 : {
1179 3069 : opt = it->second;
1180 : }
1181 : }
1182 : }
1183 :
1184 : return exact_option
1185 : ? opt
1186 10765 : : get_alias_destination(opt);
1187 : }
1188 :
1189 :
1190 : /** \brief Get an option using its short name.
1191 : *
1192 : * This function searches for an option given its short name.
1193 : *
1194 : * By default the function returns the final option. That is, if the
1195 : * named option is an alias, the destination option is returned, not
1196 : * the alias. This way the rest of the code is much simpler. You may
1197 : * get the exact option, even if it is aliased, by setting the
1198 : * \p exact_option parameter to true. It is really rare that you
1199 : * would need to do so, though.
1200 : *
1201 : * \param[in] short_name The short name of the option to look for.
1202 : * \param[in] exact_option Return the exact option, not its alias.
1203 : *
1204 : * \return The pointer to the option or nullptr if not found.
1205 : */
1206 1443 : option_info::pointer_t getopt::get_option(short_name_t short_name, bool exact_option) const
1207 : {
1208 1443 : auto it(f_options_by_short_name.find(short_name));
1209 1443 : if(it == f_options_by_short_name.end())
1210 : {
1211 1181 : return option_info::pointer_t();
1212 : }
1213 :
1214 : return exact_option
1215 7 : ? it->second
1216 269 : : get_alias_destination(it->second);
1217 : }
1218 :
1219 :
1220 : /** \brief Read parameters of the current option.
1221 : *
1222 : * This function saves the option in the list of options found in this list
1223 : * of arguments. If the option is expected to have parameters, then those
1224 : * are taken from the argv array before the function saves the option in
1225 : * the object list. The index, \p i, is increased accordingly.
1226 : *
1227 : * \warning
1228 : * This function cannot be called properly with the '-' option in case it
1229 : * is viewed as a default parameter. This is because the algorithm expects
1230 : * the index (\p i) to be pointing to the command line option and not the
1231 : * argument to that command.
1232 : *
1233 : * \param[in] opt The concerned option
1234 : * \param[in] i The current position, starting with the option position
1235 : * \param[in] argc The number of arguments in the argv array.
1236 : * \param[in] argv The list of argument strings.
1237 : */
1238 313 : void getopt::add_options(option_info::pointer_t opt, int & i, int argc, char ** argv)
1239 : {
1240 313 : if(opt->has_flag(GETOPT_FLAG_FLAG))
1241 : {
1242 134 : opt->add_value(opt->get_default());
1243 : }
1244 : else
1245 : {
1246 179 : if(i + 1 < argc && !is_arg(argv[i + 1]))
1247 : {
1248 162 : if(opt->has_flag(GETOPT_FLAG_MULTIPLE))
1249 : {
1250 32 : do
1251 : {
1252 62 : ++i;
1253 62 : opt->add_value(argv[i]);
1254 62 : } while(i + 1 < argc && !is_arg(argv[i + 1]));
1255 : }
1256 : else
1257 : {
1258 132 : ++i;
1259 132 : opt->add_value(argv[i]);
1260 : }
1261 : }
1262 : else
1263 : {
1264 17 : if(opt->has_flag(GETOPT_FLAG_REQUIRED))
1265 : {
1266 6 : cppthread::log << cppthread::log_level_t::error
1267 3 : << "option --"
1268 3 : << opt->get_name()
1269 3 : << " expects an argument."
1270 3 : << cppthread::end;
1271 : }
1272 : else
1273 : {
1274 : // We need to set something because the value is being
1275 : // set although no argument was specified (but that's
1276 : // legal by this argument's definition)
1277 : //
1278 14 : opt->add_value(std::string());
1279 : }
1280 : }
1281 : }
1282 313 : }
1283 :
1284 :
1285 : /** \brief Add an option with a value string.
1286 : *
1287 : * This function accepts a string as the value. If the option accepts
1288 : * multiple values, then the function makes use of the set_multiple_value()
1289 : * function of the option_info class. This will break the option up in
1290 : * multiple value if possible.
1291 : *
1292 : * \param[in] opt The option receiving a value.
1293 : * \param[in] value The value to assign this option.
1294 : * \param[in] filename The name of a configuration file if the option was
1295 : * read from such.
1296 : */
1297 83 : void getopt::add_option_from_string(option_info::pointer_t opt, std::string const & value, std::string const & filename)
1298 : {
1299 : // is the value defined?
1300 : //
1301 83 : if(!value.empty())
1302 : {
1303 81 : if(opt->has_flag(GETOPT_FLAG_FLAG))
1304 : {
1305 2 : cppthread::log << cppthread::log_level_t::error
1306 1 : << "option "
1307 1 : << (filename.empty()
1308 3 : ? "--" + opt->get_name()
1309 3 : : "\"" + boost::replace_all_copy(opt->get_name(), "-", "_") + "\"")
1310 1 : << " cannot be given a value"
1311 1 : << (filename.empty()
1312 3 : ? std::string()
1313 : : " in configuration file \""
1314 2 : + filename
1315 1 : + "\"")
1316 1 : << "."
1317 1 : << cppthread::end;
1318 1 : return;
1319 : }
1320 :
1321 : // does the option support multiple entries?
1322 : //
1323 80 : if(opt->has_flag(GETOPT_FLAG_MULTIPLE))
1324 : {
1325 11 : opt->set_multiple_value(value);
1326 : }
1327 : else
1328 : {
1329 69 : opt->set_value(0, value);
1330 : }
1331 :
1332 80 : return;
1333 : }
1334 :
1335 : // does the option require a value when used?
1336 : //
1337 2 : if(opt->has_flag(GETOPT_FLAG_REQUIRED))
1338 : {
1339 2 : cppthread::log << cppthread::log_level_t::error
1340 1 : << "option "
1341 1 : << (filename.empty()
1342 2 : ? "--" + opt->get_name()
1343 2 : : "\"" + boost::replace_all_copy(opt->get_name(), "-", "_") + "\"")
1344 1 : << " must be given a value"
1345 1 : << (filename.empty()
1346 2 : ? std::string()
1347 : : " in configuration file \""
1348 1 : + filename
1349 1 : + "\"")
1350 1 : << "."
1351 1 : << cppthread::end;
1352 1 : return;
1353 : }
1354 :
1355 : // accept an empty value otherwise
1356 : //
1357 1 : opt->set_value(0, value);
1358 : }
1359 :
1360 :
1361 :
1362 6 : } // namespace advgetopt
1363 : // vim: ts=4 sw=4 et
|