LCOV - code coverage report
Current view: top level - advgetopt - advgetopt.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 324 324 100.0 %
Date: 2021-09-08 17:05:25 Functions: 22 22 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13