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