LCOV - code coverage report
Current view: top level - advgetopt - advgetopt.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 358 402 89.1 %
Date: 2024-10-05 13:34:54 Functions: 21 22 95.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14

Snap C++ | List of projects | List of versions