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