LCOV - code coverage report
Current view: top level - advgetopt - option_info.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 420 463 90.7 %
Date: 2024-10-05 13:34:54 Functions: 61 62 98.4 %
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             : 
      21             : /** \file
      22             :  * \brief Implementation of the option_info class.
      23             :  *
      24             :  * This is the implementation of the class used to define one command
      25             :  * line option.
      26             :  */
      27             : 
      28             : // self
      29             : //
      30             : #include    "advgetopt/option_info.h"
      31             : 
      32             : #include    "advgetopt/exception.h"
      33             : #include    "advgetopt/validator_double.h"
      34             : #include    "advgetopt/validator_integer.h"
      35             : 
      36             : 
      37             : // cppthread
      38             : //
      39             : #include    <cppthread/guard.h>
      40             : #include    <cppthread/log.h>
      41             : #include    <cppthread/mutex.h>
      42             : 
      43             : 
      44             : // snapdev
      45             : //
      46             : #include    <snapdev/not_used.h>
      47             : #include    <snapdev/tokenize_string.h>
      48             : 
      49             : 
      50             : // libutf8
      51             : //
      52             : #include    <libutf8/libutf8.h>
      53             : #include    <libutf8/iterator.h>
      54             : 
      55             : 
      56             : // last include
      57             : //
      58             : #include    <snapdev/poison.h>
      59             : 
      60             : 
      61             : 
      62             : namespace advgetopt
      63             : {
      64             : 
      65             : 
      66             : namespace
      67             : {
      68             : 
      69             : 
      70             : /** \brief The library trace mode.
      71             :  *
      72             :  * This flag is used to determine whether the source of each option should
      73             :  * be traced. Very often, I have a problem where I'm not so sure where a
      74             :  * certain option was defined and how to fix the value of that option.
      75             :  * This flag allows us to debug that information at run time.
      76             :  *
      77             :  * When the flag is set to true (automatically done by the getopt object
      78             :  * when argv includes the "--show-sources" command line option), the sources
      79             :  * start to be traced. Once all the parsing is done, getopt again will check
      80             :  * whether it has the "--show-sources" command line option specified and if
      81             :  * so, it prints out all the options current values and the various sources
      82             :  * that were involved.
      83             :  */
      84             : bool g_trace_sources = false;
      85             : 
      86             : 
      87             : /** \brief The filename of the configuration being processed.
      88             :  *
      89             :  * This variable holds the filename of the configuration currently
      90             :  * being processed. This information is used to generate the trace
      91             :  * of the sources. That way it is possible to see where the current
      92             :  * value of a given variable comes from.
      93             :  *
      94             :  * This parameter is currently set from the
      95             :  * getopt::process_configuration_file() function.
      96             :  */
      97             : std::string g_configuration_filename = std::string();
      98             : 
      99             : 
     100             : 
     101             : } // no name namespace
     102             : 
     103             : 
     104             : 
     105             : // from utils.cpp
     106             : //
     107             : // (it's here because we do not want to make cppthread public in
     108             : // out header files--we could have an advgetopt_private.h, though)
     109             : //
     110             : cppthread::mutex &  get_global_mutex();
     111             : 
     112             : 
     113             : 
     114             : 
     115             : /** \brief Transform a string to a short name.
     116             :  *
     117             :  * This function transforms a string to a short name. The input string
     118             :  * can represent a UTF-8 character that can be used as a short name.
     119             :  *
     120             :  * An empty string is not considered to represent any name and thus
     121             :  * this function returns NO_SHORT_NAME when the input is an empty
     122             :  * string.
     123             :  *
     124             :  * \param[in] name  The name to be checked.
     125             :  *
     126             :  * \return The short name character or NO_SHORT_NAME if it's not a match.
     127             :  */
     128     2232088 : short_name_t string_to_short_name(std::string const & name)
     129             : {
     130     2232088 :     if(!name.empty())
     131             :     {
     132     2232087 :         libutf8::utf8_iterator u8(name);
     133     2232087 :         short_name_t const short_name(*u8++);
     134     2232087 :         if(u8 == name.end())
     135             :         {
     136     1112070 :             return short_name;
     137             :         }
     138             :     }
     139             : 
     140     1120018 :     return NO_SHORT_NAME;
     141             : }
     142             : 
     143             : 
     144             : /** \brief Convert a short name to a UTF-8 string.
     145             :  *
     146             :  * This function is the opposite of the to_short_name() except that the
     147             :  * input is expected to be a valid short name or NO_SHORT_NAME.
     148             :  *
     149             :  * When the input is NO_SHORT_NAME, the function outputs an empty string.
     150             :  *
     151             :  * \note
     152             :  * There are other short names that are not really considered valid such
     153             :  * as control characters, the dash (-), and probably most other
     154             :  * punctuation, character codes which are not currently assigned to
     155             :  * any character in Unicode, etc. This function ignores all of those
     156             :  * potential problems.
     157             :  *
     158             :  * \param[in] short_name  The short name to convert to UTF-8.
     159             :  *
     160             :  * \return The short name as a UTF-8 string or an empty string.
     161             :  */
     162     2224182 : std::string short_name_to_string(short_name_t short_name)
     163             : {
     164     2224182 :     if(short_name == NO_SHORT_NAME)
     165             :     {
     166           1 :         return std::string();
     167             :     }
     168     2224181 :     return libutf8::to_u8string(short_name);
     169             : }
     170             : 
     171             : 
     172             : /** \brief Create a new option_info object.
     173             :  *
     174             :  * This function creates a new option_info object with the specified \p name
     175             :  * and \p short_name. The \p short_name is optional.
     176             :  *
     177             :  * When adding options to a map of options, all the long and short names
     178             :  * must be unique. See the add_child() function for details.
     179             :  *
     180             :  * The \p short_name parameter is a UTF-32 character. To not offer a short
     181             :  * name for an option, use NO_SHORT_NAME as the value (which is the default
     182             :  * if not specified to the constructor.)
     183             :  *
     184             :  * \li Special Option Name: "--"
     185             :  *
     186             :  * The "--" long name is viewed as the separator between options and
     187             :  * \em filenames. When "--" is found by itself on the command line, then
     188             :  * it is viewed as a switch to go from having options to only having
     189             :  * \em filenames. Of course, these options may be used as any type of
     190             :  * values, not just filenames (it could be URLs, email addresses, numbers,
     191             :  * etc.)
     192             :  *
     193             :  * The "--" separator cannot be assigned a short name.
     194             :  *
     195             :  * \li Special Option Name: "*"
     196             :  *
     197             :  * The "*" long name is viewed as the \em accept \em all option. This
     198             :  * means all the options may not be defined in the list of options but
     199             :  * we still want to accept them. This is to allow dynamically defined
     200             :  * (supported) command options and especially to not have to declare
     201             :  * all the valid options found in a configuration file.
     202             :  *
     203             :  * \li Underscore and Dashes
     204             :  *
     205             :  * It is customary to support dashes between words in options appearing
     206             :  * on the command line (`--help-me`), however, it is unusual in
     207             :  * configuration files where underscores are used instead (`under_score`.)
     208             :  * When we compare option names, `'-' == '_'` is always considered true
     209             :  * so either dashes or underscore can be used in both cases.
     210             :  *
     211             :  * For this reason, the long name is saved with only dashes. That
     212             :  * means all the maps are indexed using the long name with dashes.
     213             :  *
     214             :  * \exception getopt_exception_logic
     215             :  * The constructor raises the invalid exception if the long name is an
     216             :  * empty string since this is not allowed. It will also raise that
     217             :  * exception if the name is the default option ("--") and a short name
     218             :  * is also defined. (i.e. no short name is allowed along the default
     219             :  * option.)
     220             :  *
     221             :  * \param[in] name  The (long) name of this option.
     222             :  * \param[in] short_name  The short name of this option (one character.)
     223             :  */
     224        1986 : option_info::option_info(std::string const & name, short_name_t short_name)
     225        1986 :     : f_name(option_with_dashes(name))
     226        1986 :     , f_short_name(short_name)
     227             : {
     228        1986 :     if(f_name.empty())
     229             :     {
     230           4 :         if(short_name != NO_SHORT_NAME)
     231             :         {
     232           4 :             throw getopt_logic_error(
     233             :                           "option_info::option_info(): all options must at least have a long name (short name: '"
     234           4 :                         + libutf8::to_u8string(short_name)
     235          10 :                         + "'.)");
     236             :         }
     237           2 :         throw getopt_logic_error(
     238           4 :                       "option_info::option_info(): all options must at least have a long name.");
     239             :     }
     240             : 
     241        1982 :     if(f_name == "--")
     242             :     {
     243          22 :         if(short_name != NO_SHORT_NAME)
     244             :         {
     245           4 :             throw getopt_logic_error(
     246             :                           "option_info::option_info(): the default parameter \"--\" cannot include a short name ('"
     247           4 :                         + libutf8::to_u8string(short_name)
     248          10 :                         + "'.)");
     249             :         }
     250             : 
     251          20 :         add_flag(GETOPT_FLAG_DEFAULT_OPTION);
     252             :     }
     253             :     else
     254             :     {
     255        1960 :         if(f_name[0] == '-')
     256             :         {
     257           2 :             throw getopt_logic_error(
     258             :                           "option_info::option_info(): an option cannot start with a dash (-), \""
     259           2 :                         + f_name
     260           5 :                         + "\" is not valid.");
     261             :         }
     262             : 
     263        1959 :         if(short_name == '-')
     264             :         {
     265           1 :             throw getopt_logic_error(
     266           2 :                           "option_info::option_info(): the short name of an option cannot be the dash (-).");
     267             :         }
     268             :     }
     269        2082 : }
     270             : 
     271             : 
     272             : /** \brief Get the long name of the option.
     273             :  *
     274             :  * This option retrieves the long name of the option.
     275             :  *
     276             :  * \note
     277             :  * Remember that the underscores in long names are converted to dashes.
     278             :  * This is because it makes more sense to look for command line parameters
     279             :  * with dashes. This function will return the name with only dashes.
     280             :  *
     281             :  * \note
     282             :  * The name is always defined. The creation of an option_info object
     283             :  * fails if the name is empty.
     284             :  *
     285             :  * \return The long name with dashes instead of underscores.
     286             :  */
     287        3620 : std::string const & option_info::get_name() const
     288             : {
     289        3620 :     return f_name;
     290             : }
     291             : 
     292             : 
     293             : /** \brief Assign a short name to an option.
     294             :  *
     295             :  * This function is used to assign a short name to an option.
     296             :  *
     297             :  * It can be changed to anything, including the NO_SHORT_NAME special
     298             :  * value.
     299             :  *
     300             :  * \warning
     301             :  * If you want this function to work as expected (i.e. for the option
     302             :  * to later be found using its short name), make sure to call the
     303             :  * getopt::set_short_name() on your getopt object and not directly this
     304             :  * function. This is because the getopt object needs to add the newly
     305             :  * named option to its map of options sorted by short name.
     306             :  *
     307             :  * \param[in] short_name  The short name to assign to this option.
     308             :  *
     309             :  * \sa get_short_name()
     310             :  * \sa getopt::set_short_name()
     311             :  */
     312         198 : void option_info::set_short_name(short_name_t short_name)
     313             : {
     314         198 :     f_short_name = short_name;
     315         198 : }
     316             : 
     317             : 
     318             : /** \brief Get the short name of the option.
     319             :  *
     320             :  * This function returns the \p short_name of this option.
     321             :  *
     322             :  * The short name is a Unicode character (UTF-32).
     323             :  *
     324             :  * \return The short name character.
     325             :  */
     326        1920 : short_name_t option_info::get_short_name() const
     327             : {
     328        1920 :     return f_short_name;
     329             : }
     330             : 
     331             : 
     332             : /** \brief Retrieve the name of the option without any section names.
     333             :  *
     334             :  * The name of an option can include section names. These
     335             :  * are rarely used on the command line, but they are useful for
     336             :  * configuration files if you want to create multiple layers of
     337             :  * options (a.k.a. sections.)
     338             :  *
     339             :  * This function removes all the section names from the option name
     340             :  * and returns what's left.
     341             :  *
     342             :  * \return The base name without any section names.
     343             :  */
     344           4 : std::string option_info::get_basename() const
     345             : {
     346           4 :     std::string::size_type const pos(f_name.rfind("::"));
     347           4 :     if(pos == std::string::npos)
     348             :     {
     349           1 :         return f_name;
     350             :     }
     351             : 
     352           3 :     return f_name.substr(pos + 2);
     353             : }
     354             : 
     355             : 
     356             : /** \brief Retrieve the name of the sections.
     357             :  *
     358             :  * The name of an option can include section names. These
     359             :  * are rarely used on the command line, but they are useful for
     360             :  * configuration files if you want to create multiple layers of
     361             :  * options (a.k.a. sections.)
     362             :  *
     363             :  * This function returns all the section names found in this option
     364             :  * name. The last scope operator gets removed too.
     365             :  *
     366             :  * If the name does not include any sections, then this function returns
     367             :  * an empty string.
     368             :  *
     369             :  * \return The section names without the basename.
     370             :  */
     371           4 : std::string option_info::get_section_name() const
     372             : {
     373           4 :     std::string::size_type const pos(f_name.rfind("::"));
     374           4 :     if(pos == std::string::npos)
     375             :     {
     376           1 :         return std::string();
     377             :     }
     378             : 
     379           3 :     return f_name.substr(0, pos);
     380             : }
     381             : 
     382             : 
     383             : /** \brief Retrieve a list of section names.
     384             :  *
     385             :  * The name of an option can include section names. These
     386             :  * are rarely used on the command line, but they are useful for
     387             :  * configuration files if you want to create multiple layers of
     388             :  * options (a.k.a. sections.)
     389             :  *
     390             :  * This function returns a string_list_t of the section names found in
     391             :  * this option name.
     392             :  *
     393             :  * If the name does not include any sections, then this function returns
     394             :  * an empty list.
     395             :  *
     396             :  * \return The list of section name.
     397             :  */
     398           4 : string_list_t option_info::get_section_name_list() const
     399             : {
     400           4 :     std::string::size_type const pos(f_name.rfind("::"));
     401           4 :     if(pos == std::string::npos)
     402             :     {
     403           1 :         return string_list_t();
     404             :     }
     405             : 
     406           3 :     string_list_t section_list;
     407          12 :     snapdev::tokenize_string(section_list
     408           6 :                         , f_name.substr(0, pos)
     409             :                         , "::"
     410             :                         , true
     411           6 :                         , std::string()
     412             :                         , &snapdev::string_predicate<string_list_t>);
     413           3 :     return section_list;
     414           3 : }
     415             : 
     416             : 
     417             : /** \brief Check whether this is the default option.
     418             :  *
     419             :  * This function checks whether this option represents the default option.
     420             :  * The default option is where non-options, generally filenames, are added
     421             :  * when not following an argument.
     422             :  *
     423             :  * The name of the default option is always "--". However, it is not
     424             :  * required. When no default option is defined, filenames can't be
     425             :  * specified and when such are found on the command line, an error
     426             :  * ensues.
     427             :  *
     428             :  * \return true if the name of the option is "--".
     429             :  */
     430        2046 : bool option_info::is_default_option() const
     431             : {
     432        2046 :     return has_flag(GETOPT_FLAG_DEFAULT_OPTION)
     433        2046 :         || (f_name.size() == 2 && f_name[0] == '-' && f_name[1] == '-');
     434             : }
     435             : 
     436             : 
     437             : /** \brief Set the option specific environment variable name.
     438             :  *
     439             :  * Each option can be given a specific environment variable name. That
     440             :  * parameter is used to retrieve the option value if not defined on the
     441             :  * command line.
     442             :  *
     443             :  * By default this is an empty string.
     444             :  *
     445             :  * \param[in] name  The name of the environment variable attached to this
     446             :  * option.
     447             :  *
     448             :  * \sa get_environment_variable_name()
     449             :  * \sa get_environment_variable_value()
     450             :  */
     451          30 : void option_info::set_environment_variable_name(std::string const & name)
     452             : {
     453          30 :     f_environment_variable_name = name;
     454          30 : }
     455             : 
     456             : 
     457             : /** \brief Set the default value of this option.
     458             :  *
     459             :  * This function is an overload which allows us to call set_default()
     460             :  * with a nullptr.
     461             :  *
     462             :  * \param[in] default_value  The new default value for this option.
     463             :  *
     464             :  * \sa get_environment_variable_name()
     465             :  * \sa get_environment_variable_value()
     466             :  */
     467        1647 : void option_info::set_environment_variable_name(char const * name)
     468             : {
     469        1647 :     if(name != nullptr)
     470             :     {
     471          22 :         set_environment_variable_name(std::string(name));
     472             :     }
     473        1647 : }
     474             : 
     475             : 
     476             : /**  \brief Retrieve the environment variable name of this option.
     477             :  *
     478             :  * Each command line option can be assigned an environment variable
     479             :  * name. When checking for the global environment variable name, the
     480             :  * advgetopt library also checks each option's environment variable
     481             :  * name which has priority over the global variable (i.e. it will
     482             :  * overwrite a value found in the global environment variable).
     483             :  *
     484             :  * The value returned is an empty string by default, which means the
     485             :  * option does not have a value defined in an environment variable.
     486             :  *
     487             :  * \return The environment variable name of this option.
     488             :  *
     489             :  * \sa set_environment_variable_name()
     490             :  * \sa get_environment_variable_value()
     491             :  */
     492        1491 : std::string option_info::get_environment_variable_name() const
     493             : {
     494        1491 :     return f_environment_variable_name;
     495             : }
     496             : 
     497             : 
     498             : /**  \brief Retrieve the environment variable value of this option.
     499             :  *
     500             :  * Each command line option can be assigned an environment variable
     501             :  * name. Using this name, this function attempts to retrieve the
     502             :  * corresponding value defined in that variable.
     503             :  *
     504             :  * \param[out] value  Save the resulting value in this variable.
     505             :  * \param[in] intro  The introducer to prepend. May be nullptr.
     506             :  *
     507             :  * \return true if a value was defined.
     508             :  *
     509             :  * \sa set_environment_variable_name()
     510             :  * \sa get_environment_variable_name()
     511             :  */
     512        1322 : bool option_info::get_environment_variable_value(
     513             :           std::string & value
     514             :         , char const * intro) const
     515             : {
     516             :     // make it empty by default
     517             :     //
     518        1322 :     value.clear();
     519             : 
     520        1322 :     if(f_environment_variable_name.empty())
     521             :     {
     522        1290 :         return false;
     523             :     }
     524             : 
     525          32 :     std::string name(f_environment_variable_name);
     526          32 :     if(intro != nullptr)
     527             :     {
     528           2 :         name = intro + name;
     529             :     }
     530             : 
     531          32 :     char const * env(getenv(name.c_str()));
     532          32 :     if(env == nullptr)
     533             :     {
     534          19 :         return false;
     535             :     }
     536             : 
     537          13 :     value = env;
     538             : 
     539          13 :     return true;
     540          32 : }
     541             : 
     542             : 
     543             : /** \brief Get the flags.
     544             :  *
     545             :  * The options have flags determining various sub-options available
     546             :  * to them. Right now we have flags to tell how each option can be
     547             :  * used (on the command line, in an environment variable, or in
     548             :  * a configuration file.)
     549             :  *
     550             :  * \note
     551             :  * We have the GETOPT_FLAG_ALIAS flag which is used to define
     552             :  * an alias. That means values do not get set in an option which
     553             :  * is marked as an alias. Instead, they get set in the option
     554             :  * which is being aliased. This means your software does not have
     555             :  * to check both options. The setup function will actually call
     556             :  * the set_alias() function at some point to finalize aliases
     557             :  * so you do not really need the flag, except to know that no
     558             :  * value will be defined here because it will instead be saved
     559             :  * in the aliased option.
     560             :  *
     561             :  * \param[in] flags  The new flags.
     562             :  */
     563        2323 : void option_info::set_flags(flag_t flags)
     564             : {
     565        2323 :     f_flags = flags;
     566        2323 : }
     567             : 
     568             : 
     569             : /** \brief Make sure a given flag is set.
     570             :  *
     571             :  * This function adds the given flag from the set of flags being set.
     572             :  *
     573             :  * \note
     574             :  * Multiple flags can be defined in \p flag.
     575             :  *
     576             :  * \param[in] flag  The flag(s) to set.
     577             :  */
     578        2210 : void option_info::add_flag(flag_t flag)
     579             : {
     580        2210 :     set_flags(f_flags | flag);
     581        2210 : }
     582             : 
     583             : 
     584             : /** \brief Make sure a given flag is not set.
     585             :  *
     586             :  * This function removes the given flag from the set of flags currently set.
     587             :  *
     588             :  * \note
     589             :  * Multiple flags can be defined in \p flag.
     590             :  *
     591             :  * \param[in] flag  The flag(s) to clear.
     592             :  */
     593          46 : void option_info::remove_flag(flag_t flag)
     594             : {
     595          46 :     set_flags(f_flags & ~flag);
     596          46 : }
     597             : 
     598             : 
     599             : /** \brief Retrieve the flags.
     600             :  *
     601             :  * This function retrieves all the flags defined in this option.
     602             :  *
     603             :  * To just check whether a flag is set or not, use the has_flag()
     604             :  * function instead.
     605             :  *
     606             :  * \return This option flags.
     607             :  */
     608        1187 : flag_t option_info::get_flags() const
     609             : {
     610        1187 :     return f_flags;
     611             : }
     612             : 
     613             : 
     614             : /** \brief Check whether a flag is set.
     615             :  *
     616             :  * This function is used to check whether a flag is set or not.
     617             :  *
     618             :  * \note
     619             :  * The \p flag parameter can be set to more than one flag in which case
     620             :  * the function returns true if any one of those flags is set.
     621             :  *
     622             :  * \return true if the flag is set, false otherwise.
     623             :  */
     624       23397 : bool option_info::has_flag(flag_t flag) const
     625             : {
     626       23397 :     return (f_flags & flag) != 0;
     627             : }
     628             : 
     629             : 
     630             : /** \brief Check whether this option has a default value.
     631             :  *
     632             :  * Whenever an option is given a default value, the GETOPT_FLAG_HAS_DEFAULT
     633             :  * flag gets set. This allows us to distinguish between an option with a
     634             :  * default which is the empty string and an option without a default.
     635             :  *
     636             :  * The set_default() forces the flag to be set.
     637             :  *
     638             :  * The remove_default() clears the flag.
     639             :  *
     640             :  * \return true if the flag is set, false otherwise.
     641             :  *
     642             :  * \sa set_default()
     643             :  * \sa remove_default()
     644             :  * \sa get_default()
     645             :  */
     646         403 : bool option_info::has_default() const
     647             : {
     648         403 :     return has_flag(GETOPT_FLAG_HAS_DEFAULT);
     649             : }
     650             : 
     651             : 
     652             : /** \brief Set the default value.
     653             :  *
     654             :  * This function sets the default value for this option.
     655             :  *
     656             :  * The default value is always defined as a string, but it can later be
     657             :  * converted to a different type using the option validator.
     658             :  *
     659             :  * Often, though, the default value is not compatible with the validator.
     660             :  * For example, you may have a parameter which is set to a percentage
     661             :  * from -100% to +100% and the default may be the string "off".
     662             :  *
     663             :  * \note
     664             :  * After calling this function, the option is viewed as having a default
     665             :  * even if that's the empty string.
     666             :  *
     667             :  * \param[in] default_value  The new default value for this option.
     668             :  *
     669             :  * \sa remove_default()
     670             :  * \sa has_default()
     671             :  * \sa get_default()
     672             :  */
     673         133 : void option_info::set_default(std::string const & default_value)
     674             : {
     675         133 :     f_default_value = default_value;
     676         133 :     add_flag(GETOPT_FLAG_HAS_DEFAULT);
     677         133 : }
     678             : 
     679             : 
     680             : /** \brief Set the default value of this option.
     681             :  *
     682             :  * This function is an overload which allows us to call set_default()
     683             :  * with a nullptr.
     684             :  *
     685             :  * \param[in] default_value  The new default value for this option.
     686             :  *
     687             :  * \sa remove_default()
     688             :  * \sa has_default()
     689             :  * \sa get_default()
     690             :  */
     691        1650 : void option_info::set_default(char const * default_value)
     692             : {
     693        1650 :     if(default_value != nullptr)
     694             :     {
     695         111 :         set_default(std::string(default_value));
     696             :     }
     697        1650 : }
     698             : 
     699             : 
     700             : /** \brief Remove the default value.
     701             :  *
     702             :  * Call this function remove the default value. The default string gets
     703             :  * cleared and the GETOPT_FLAG_NO_DEFAULT flag gets set.
     704             :  *
     705             :  * \sa set_default()
     706             :  * \sa has_default()
     707             :  * \sa get_default()
     708             :  */
     709           4 : void option_info::remove_default()
     710             : {
     711           4 :     f_default_value.clear();
     712           4 :     remove_flag(GETOPT_FLAG_HAS_DEFAULT);
     713           4 : }
     714             : 
     715             : 
     716             : /** \brief Retrieve the default value.
     717             :  *
     718             :  * This function returns the default value.
     719             :  *
     720             :  * \return The default string value.
     721             :  */
     722         807 : std::string const & option_info::get_default() const
     723             : {
     724         807 :     return f_default_value;
     725             : }
     726             : 
     727             : 
     728             : /** \brief Set the help string for this option.
     729             :  *
     730             :  * The usage() function prints this string whenever the command
     731             :  * line includes the help command line option (such as `-h` or
     732             :  * `--help`.)
     733             :  *
     734             :  * The string can include various flags such as `%p` to include
     735             :  * dynamically defined parameters. See the process_help_string()
     736             :  * function for additional details about these parameters.
     737             :  *
     738             :  * \note
     739             :  * When using a special flag (i.e. GETOPT_FLAG_HELP), the help value
     740             :  * string is used as the value used by that special feature:
     741             :  *
     742             :  * \li GETOPT_FLAG_HELP
     743             :  *
     744             :  * It represents a string to print out by the usage() function. The option
     745             :  * purpose is solaly for adding a string of help in the output.
     746             :  *
     747             :  * \li GETOPT_FLAG_EXTERNAL_OPTIONS
     748             :  *
     749             :  * It represents the filename to read additional advgetopt options. In
     750             :  * some cases, your static array of option structures is to define this
     751             :  * special flag.
     752             :  *
     753             :  * \li GETOPT_FLAG_LICENSE
     754             :  *
     755             :  * It represents the program license.
     756             :  *
     757             :  * \li GETOPT_FLAG_COPYRIGHT
     758             :  *
     759             :  * It represents the program copyright notice.
     760             :  *
     761             :  * \param[in] help  The help string for this option.
     762             :  */
     763        1875 : void option_info::set_help(std::string const & help)
     764             : {
     765        1875 :     f_help = help;
     766        1875 : }
     767             : 
     768             : 
     769             : /** \brief Set the help string for this option.
     770             :  *
     771             :  * This function is an overload which allows us to call set_help() with
     772             :  * a nullptr and not crash. We just ignore the call when that happens.
     773             :  *
     774             :  * \param[in] help  The help string for this option or nullptr.
     775             :  */
     776        1844 : void option_info::set_help(char const * help)
     777             : {
     778        1844 :     if(help != nullptr)
     779             :     {
     780        1827 :         set_help(std::string(help));
     781             :     }
     782        1844 : }
     783             : 
     784             : 
     785             : /** \brief Get the help string.
     786             :  *
     787             :  * This function returns the help string for this command line option.
     788             :  *
     789             :  * \warning
     790             :  * Note that when a special flag is set, this string may represent something
     791             :  * else that a help string.
     792             :  *
     793             :  * \return The help string of this argument.
     794             :  */
     795         330 : std::string const & option_info::get_help() const
     796             : {
     797         330 :     return f_help;
     798             : }
     799             : 
     800             : 
     801             : /** \brief Set the validator for this option.
     802             :  *
     803             :  * This function parses the specified name and optional parameters and
     804             :  * create a corresponding validator for this option.
     805             :  *
     806             :  * The \p name_and_params string can be defined as one of:
     807             :  *
     808             :  * \code
     809             :  *     <validator-name>
     810             :  *     <validator-name>()
     811             :  *     <validator-name>(<param1>)
     812             :  *     <validator-name>(<param1>, <param2>, ...)
     813             :  * \endcode
     814             :  *
     815             :  * The list of parameters is optional. There may be no, just one,
     816             :  * or any number of parameters. How the parameters are parsed is left
     817             :  * to the validator to decide.
     818             :  *
     819             :  * If the input string is empty, the current validator, if one is
     820             :  * installed, gets removed.
     821             :  *
     822             :  * \note
     823             :  * If the option_info already has a set of values, they get validated
     824             :  * against the new validator. Any value which does not validate gets
     825             :  * removed at once. The validation process also generates an error
     826             :  * when an invalid error is found. Note that it is expected that you
     827             :  * will setup a validator before you start parsing data so this feature
     828             :  * should seldom be used.
     829             :  *
     830             :  * \param[in] name_and_params  The validator name and parameters.
     831             :  *
     832             :  * \return true if the validator was installed and all existing values were
     833             :  *         considered valid.
     834             :  */
     835          47 : bool option_info::set_validator(std::string const & name_and_params)
     836             : {
     837          47 :     return set_validator(validator::create(name_and_params));
     838             : }
     839             : 
     840             : 
     841             : /** \brief Set the validator for this option.
     842             :  *
     843             :  * Options may be assigned a validator. Without a validator, any value
     844             :  * is considered valid.
     845             :  *
     846             :  * A value is checked when you call the validates() function. The function
     847             :  * returns true if the value is considered valid. False in all other cases.
     848             :  *
     849             :  * You can define your own validators and add them to the library list of
     850             :  * available validators before using the library in order to get your
     851             :  * options to use said validators.
     852             :  *
     853             :  * \note
     854             :  * If the option_info already has a set of values, they get validated
     855             :  * against the new validator. Any value which does not validate gets
     856             :  * removed at once. The validation process also generates an error
     857             :  * when an invalid error is found. Note that it is expected that you
     858             :  * will setup a validator before you start parsing data so this feature
     859             :  * should seldom be used.
     860             :  *
     861             :  * \param[in] validator  A pointer to a validator.
     862             :  *
     863             :  * \return true if the validator was installed and all existing values were
     864             :  *         considered valid.
     865             :  */
     866          49 : bool option_info::set_validator(validator::pointer_t validator)
     867             : {
     868          49 :     f_validator = validator;
     869             : 
     870             :     // make sure that all existing values validate against this
     871             :     // new validator
     872             :     //
     873          49 :     std::size_t const size(f_value.size());
     874          49 :     bool const r(validate_all_values());
     875          49 :     if(size != f_value.size())
     876             :     {
     877           3 :         value_changed(0);
     878             :     }
     879          49 :     return r;
     880             : }
     881             : 
     882             : 
     883             : /** \brief Clear the validator.
     884             :  *
     885             :  * This function removes the existing validator by resetting the pointer
     886             :  * back to nullptr.
     887             :  *
     888             :  * \param[in] null_ptr  Ignored.
     889             :  *
     890             :  * \return Always true since no validator means any existing values would
     891             :  *         be considered valid.
     892             :  */
     893           5 : bool option_info::set_validator(std::nullptr_t null_ptr)
     894             : {
     895           5 :     snapdev::NOT_USED(null_ptr);
     896             : 
     897           5 :     f_validator.reset();
     898             : 
     899           5 :     return true;
     900             : }
     901             : 
     902             : 
     903             : /** \brief Check a value validity.
     904             :  *
     905             :  * This function us used internally to verify values that get added at
     906             :  * the time they get added. It runs the validator::validate() function
     907             :  * and returns true if the value is considered valid. When the value
     908             :  * does not validate, it returns false and removes the value from the
     909             :  * f_value vector. This means no invalid values are ever kept in an
     910             :  * option_info object.
     911             :  *
     912             :  * An option without a validator has values that are always valid.
     913             :  * Also, an empty value is always considered valid.
     914             :  *
     915             :  * \note
     916             :  * This function is private since there is no need for the user of
     917             :  * the option_info to ever call it (i.e. it automatically gets called
     918             :  * any time a value gets added to the f_value vector.)
     919             :  *
     920             :  * \param[in] idx  The value to check.
     921             :  *
     922             :  * \return true if the value is considered valid, false otherwise.
     923             :  */
     924         683 : bool option_info::validates(int idx)
     925             : {
     926         683 :     if(static_cast<size_t>(idx) >= f_value.size())
     927             :     {
     928             :         throw getopt_undefined(                                         // LCOV_EXCL_LINE
     929             :                       "option_info::validates(): no value at index "    // LCOV_EXCL_LINE
     930             :                     + std::to_string(idx)                               // LCOV_EXCL_LINE
     931             :                     + " (idx >= "                                       // LCOV_EXCL_LINE
     932             :                     + std::to_string(f_value.size())                    // LCOV_EXCL_LINE
     933             :                     + ") for --"                                        // LCOV_EXCL_LINE
     934             :                     + f_name                                            // LCOV_EXCL_LINE
     935             :                     + " so you can't get this value.");                 // LCOV_EXCL_LINE
     936             :     }
     937             : 
     938             :     // the value is considered valid when:
     939             :     //   * there is no validator
     940             :     //   * if the value is empty
     941             :     //   * when the value validate against the specified validator
     942             :     //
     943         683 :     if(f_validator == nullptr
     944          73 :     || f_value[idx].empty()
     945         756 :     || f_validator->validate(f_value[idx]))
     946             :     {
     947         665 :         return true;
     948             :     }
     949             : 
     950          36 :     cppthread::log << cppthread::log_level_t::error
     951          18 :                    << "input \""
     952          18 :                    << f_value[idx]
     953          18 :                    << "\" given to parameter --"
     954          18 :                    << f_name
     955          18 :                    << " is not considered valid."
     956          36 :                    << cppthread::end;
     957             : 
     958             :     // get rid of that value since it does not validate
     959             :     //
     960          18 :     f_value.erase(f_value.begin() + idx);
     961          18 :     if(f_value.empty())
     962             :     {
     963          10 :         f_source = option_source_t::SOURCE_UNDEFINED;
     964             :     }
     965             : 
     966          18 :     return false;
     967             : }
     968             : 
     969             : 
     970             : /** \brief Retrieve a pointer to the validator.
     971             :  *
     972             :  * The validator of an option may be used for additional tasks such as
     973             :  * converting the value to a specific type (i.e. a string to an
     974             :  * integer, for example.)
     975             :  *
     976             :  * This function allows you to retrieve the validator to be able to
     977             :  * make use of those functions. You will have to use
     978             :  * std::dynamic_cast_pointer<>() to change the type of validator to
     979             :  * the specialized validator of this option. If that returns a null
     980             :  * pointer, then the option is not using that type of validator.
     981             :  *
     982             :  * \todo
     983             :  * Add a template function that does the cast for the caller.
     984             :  *
     985             :  * \return A pointer to this option validator.
     986             :  */
     987          26 : validator::pointer_t option_info::get_validator() const
     988             : {
     989          26 :     return f_validator;
     990             : }
     991             : 
     992             : 
     993             : /** \brief Set the alias option.
     994             :  *
     995             :  * After loading all the options, we run the link_aliases() function which
     996             :  * makes sure that all the options that are marked as an alias are
     997             :  * properly linked.
     998             :  *
     999             :  * \param[in] alias  The final destination of this option.
    1000             :  */
    1001          21 : void option_info::set_alias_destination(option_info::pointer_t destination)
    1002             : {
    1003          21 :     if(destination->has_flag(GETOPT_FLAG_ALIAS))
    1004             :     {
    1005           1 :         throw getopt_invalid(
    1006             :                 "option_info::set_alias(): you can't set an alias as"
    1007           2 :                 " an alias of another option.");
    1008             :     }
    1009             : 
    1010          20 :     f_alias_destination = destination;
    1011          20 : }
    1012             : 
    1013             : 
    1014             : /** \brief Get a link to the destination alias.
    1015             :  *
    1016             :  * This function returns a pointer to the aliased option.
    1017             :  *
    1018             :  * \return The alias or a nullptr.
    1019             :  */
    1020         113 : option_info::pointer_t option_info::get_alias_destination() const
    1021             : {
    1022         113 :     return f_alias_destination;
    1023             : }
    1024             : 
    1025             : 
    1026             : /** \brief Set the list of separators.
    1027             :  *
    1028             :  * Options marked with the GETOPT_FLAG_MULTIPLE flag
    1029             :  * get their value cut by separators when such is found in an
    1030             :  * environment variable or a configuration file.
    1031             :  *
    1032             :  * This function saves the list of separators in a vector.
    1033             :  *
    1034             :  * \todo
    1035             :  * At the moment, this is only applied when the parameter is specified with
    1036             :  * the long option and an equal sign, as in: `--tags=a,b,c,d`. I thinks that
    1037             :  * it should also work without the equal sign.
    1038             :  *
    1039             :  * \param[in] separators  The list of separators to be used for this argument.
    1040             :  */
    1041        1651 : void option_info::set_multiple_separators(char const * const * separators)
    1042             : {
    1043        1651 :     f_multiple_separators.clear();
    1044        1651 :     if(separators == nullptr)
    1045             :     {
    1046        1632 :         return;
    1047             :     }
    1048             : 
    1049          46 :     for(; *separators != nullptr; ++separators)
    1050             :     {
    1051          27 :         f_multiple_separators.push_back(*separators);
    1052             :     }
    1053             : }
    1054             : 
    1055             : 
    1056             : /** \brief Set the list of separators.
    1057             :  *
    1058             :  * Options marked with the GETOPT_FLAG_MULTIPLE flag
    1059             :  * get their value cut by separators when such is found in an
    1060             :  * environment variable or a configuration file.
    1061             :  *
    1062             :  * This function saves the specified list of separators.
    1063             :  *
    1064             :  * \todo
    1065             :  * See the other set_multiple_separators() function about the issue of
    1066             :  * the separators not being used in all cases.
    1067             :  *
    1068             :  * \param[in] separators  The list of separators to be used for this argument.
    1069             :  */
    1070           7 : void option_info::set_multiple_separators(string_list_t const & separators)
    1071             : {
    1072           7 :     f_multiple_separators = separators;
    1073           7 : }
    1074             : 
    1075             : 
    1076             : /** \brief Retrieve the list of separators for this argument.
    1077             :  *
    1078             :  * This function returns a reference to the list of separators of this
    1079             :  * option. It is expected to be used when a value is found in a
    1080             :  * configuration file or a command line in an environment variable.
    1081             :  * Parameters on the command line are already broken down by the
    1082             :  * shell and we do not do any further manipulation with those.
    1083             :  *
    1084             :  * \warning
    1085             :  * As mentioned in the set_multiple_separators() function, the separators
    1086             :  * are only used when parsing a long parameter using the equal sign notation
    1087             :  * (i.e. `--tags=a,b,c,d`). It also works in environment variables. I am
    1088             :  * thinking that the `--tags a,b,c,d` should probably work the same way
    1089             :  * though because otherwise many people will have a surprise.
    1090             :  *
    1091             :  * \return A reference to the list of separators used to cut multiple
    1092             :  *         arguments found in a configuration file or an environment
    1093             :  *         variable.
    1094             :  */
    1095           9 : string_list_t const & option_info::get_multiple_separators() const
    1096             : {
    1097           9 :     return f_multiple_separators;
    1098             : }
    1099             : 
    1100             : 
    1101             : /** \brief Assign variables to this option info.
    1102             :  *
    1103             :  * The getopt object holds a set of variables which is can pass down to
    1104             :  * the option info. If defined, then the get_value() function returns
    1105             :  * a processed value (a.k.a. the `${...}` references in that value are
    1106             :  * replaced by their corresponding value).
    1107             :  *
    1108             :  * \param[in] vars  A pointer to a list of variables.
    1109             :  */
    1110        1736 : void option_info::set_variables(variables::pointer_t vars)
    1111             : {
    1112        1736 :     f_variables = vars;
    1113        1736 : }
    1114             : 
    1115             : 
    1116             : /** \brief Retrieve the list of variables held by this option info.
    1117             :  *
    1118             :  * This option info object may replace variables in values (see get_value()
    1119             :  * for details) using this list of variables. Option info objects created
    1120             :  * by the getopt class always have this pointer set, although the list of
    1121             :  * variables may be empty.
    1122             :  *
    1123             :  * \return A pointer to the list of variables found in the option info object.
    1124             :  */
    1125           6 : variables::pointer_t option_info::get_variables() const
    1126             : {
    1127           6 :     return f_variables;
    1128             : }
    1129             : 
    1130             : 
    1131             : /** \brief Check whether one of the values matches the input.
    1132             :  *
    1133             :  * This function searches the set of existing values in this option_info
    1134             :  * and if found returns true.
    1135             :  *
    1136             :  * \note
    1137             :  * It is possible to add the same value multiple times. However, there are
    1138             :  * cases where you may not want to have the same value more than once.
    1139             :  * This function can be used to try to not do that.
    1140             :  *
    1141             :  * \param[in] value  The value to search in this option.
    1142             :  *
    1143             :  * \return true if the value is already defined in this option_info.
    1144             :  *
    1145             :  * \sa set_value()
    1146             :  */
    1147          10 : bool option_info::has_value(std::string const & value) const
    1148             : {
    1149          10 :     auto const it(std::find(f_value.begin(), f_value.end(), value));
    1150          20 :     return it != f_value.end();
    1151             : }
    1152             : 
    1153             : 
    1154             : /** \brief Add a value to this option.
    1155             :  *
    1156             :  * Whenever an option is found it may be followed by one or more values.
    1157             :  * This function is used to add these values to this option.
    1158             :  *
    1159             :  * Later you can use the size() function to know how many values were
    1160             :  * added and the get_value() to retrieve any one of these values.
    1161             :  *
    1162             :  * \warning
    1163             :  * This function sets the value at offset 0 if it is already defined and
    1164             :  * the GETOPT_FLAG_MULTIPLE flag is not set in this option. In other words,
    1165             :  * you can't use this function to add multiple values if this option does
    1166             :  * not support that feature.
    1167             :  *
    1168             :  * \param[in] value  The value to add to this option.
    1169             :  * \param[in] option_keys  The set of keys found at the end of the option name.
    1170             :  * \param[in] source  Where the value comes from.
    1171             :  *
    1172             :  * \return true when the value was accepted (no error occurred).
    1173             :  *
    1174             :  * \sa set_value()
    1175             :  */
    1176         508 : bool option_info::add_value(
    1177             :       std::string const & value
    1178             :     , string_list_t const & option_keys
    1179             :     , option_source_t source)
    1180             : {
    1181         508 :     return set_value(
    1182         508 :               has_flag(GETOPT_FLAG_MULTIPLE)
    1183         147 :                     ? f_value.size()
    1184             :                     : 0
    1185             :             , value
    1186             :             , option_keys
    1187         508 :             , source);
    1188             : }
    1189             : 
    1190             : 
    1191             : /** \brief Replace a value.
    1192             :  *
    1193             :  * This function is generally used to replace an existing value. If the
    1194             :  * index is set to the size of the existing set of values, then a new
    1195             :  * value is saved in the vector.
    1196             :  *
    1197             :  * This is particularly useful if you want to edit a configuration file.
    1198             :  *
    1199             :  * If the option comes with a validator, then the value gets checked
    1200             :  * against that validator. If that results in an error, the value is
    1201             :  * not added to the vector so an invalid value will never be returned
    1202             :  * by the option_info class.
    1203             :  *
    1204             :  * The value does not get added when it currently is locked or when
    1205             :  * it does not validate as per the validator of this option_info.
    1206             :  *
    1207             :  * \exception getopt_exception_undefined
    1208             :  * If the index is out of range (too large or negative), then this
    1209             :  * exception is raised.
    1210             :  *
    1211             :  * \param[in] idx  The position of the value to update.
    1212             :  * \param[in] value  The new value.
    1213             :  * \param[in] option_keys  An array of keys to prepend to each value.
    1214             :  * \param[in] source  Where the value comes from.
    1215             :  *
    1216             :  * \return true if the set_value() added the value.
    1217             :  *
    1218             :  * \sa add_value()
    1219             :  * \sa validates()
    1220             :  * \sa lock()
    1221             :  * \sa unlock()
    1222             :  */
    1223         701 : bool option_info::set_value(
    1224             :       int idx
    1225             :     , std::string const & value
    1226             :     , string_list_t const & option_keys
    1227             :     , option_source_t source)
    1228             : {
    1229         701 :     if(source == option_source_t::SOURCE_UNDEFINED)
    1230             :     {
    1231           2 :         throw getopt_logic_error(
    1232             :                   "option_info::set_value(): called with SOURCE_UNDEFINED ("
    1233           2 :                 + std::to_string(static_cast<int>(source))
    1234           5 :                 + ").");
    1235             :     }
    1236             : 
    1237         700 :     if(has_flag(GETOPT_FLAG_LOCK))
    1238             :     {
    1239           8 :         return false;
    1240             :     }
    1241             : 
    1242         692 :     if(source == option_source_t::SOURCE_DIRECT
    1243         692 :     && !has_flag(GETOPT_FLAG_DYNAMIC_CONFIGURATION))
    1244             :     {
    1245           2 :         cppthread::log << cppthread::log_level_t::error
    1246           1 :                        << "option \"--"
    1247           1 :                        << f_name
    1248           1 :                        << "\" can't be directly updated."
    1249           2 :                        << cppthread::end;
    1250           1 :         return false;
    1251             :     }
    1252             : 
    1253         691 :     bool const multiple(has_flag(GETOPT_FLAG_MULTIPLE));
    1254         691 :     if(multiple)
    1255             :     {
    1256         163 :         if(static_cast<size_t>(idx) > f_value.size())
    1257             :         {
    1258           4 :             throw getopt_logic_error(
    1259             :                       "option_info::set_value(): no value at index "
    1260           4 :                     + std::to_string(idx)
    1261           6 :                     + " and it is not the last available index + 1 (idx > "
    1262           8 :                     + std::to_string(f_value.size())
    1263          10 :                     + ") so you can't set this value (try add_value() maybe?).");
    1264             :         }
    1265             :     }
    1266             :     else
    1267             :     {
    1268         528 :         if(idx != 0)
    1269             :         {
    1270           4 :             throw getopt_logic_error(
    1271             :                           "option_info::set_value(): single value option \"--"
    1272           4 :                         + f_name
    1273           6 :                         + "\" does not accepts index "
    1274           8 :                         + std::to_string(idx)
    1275          10 :                         + " which is not 0.");
    1276             :         }
    1277             :     }
    1278             : 
    1279         687 :     f_source = source;
    1280         687 :     f_integer.clear();
    1281         687 :     f_double.clear();
    1282             : 
    1283         687 :     bool r(true);
    1284         687 :     if(option_keys.empty())
    1285             :     {
    1286         687 :         if(static_cast<size_t>(idx) == f_value.size())
    1287             :         {
    1288         565 :             f_value.push_back(value);
    1289             :         }
    1290             :         else
    1291             :         {
    1292         122 :             if(f_value[idx] == value)
    1293             :             {
    1294             :                 // no change, we can return as is
    1295             :                 //
    1296             :                 // note: we know that the value is valid here since the
    1297             :                 //       validates() function removes invalid values from
    1298             :                 //       the f_value array
    1299             :                 //
    1300          22 :                 return true;
    1301             :             }
    1302         100 :             f_value[idx] = value;
    1303             :         }
    1304             : 
    1305         665 :         if(validates(idx))
    1306             :         {
    1307         656 :             value_changed(idx);
    1308             :         }
    1309             :         else
    1310             :         {
    1311           9 :             r = false;
    1312             :         }
    1313             :     }
    1314             :     else
    1315             :     {
    1316           0 :         bool changed(false);
    1317           0 :         bool const append(multiple && idx >= static_cast<int>(f_value.size()));
    1318           0 :         for(auto const & k : option_keys)
    1319             :         {
    1320           0 :             bool new_value(true);
    1321           0 :             std::string const v(k + value);
    1322           0 :             idx = append ? -1 : find_value_index_by_key(k);
    1323           0 :             if(idx == -1)
    1324             :             {
    1325           0 :                 f_value.push_back(v);
    1326           0 :                 changed = true;
    1327             :             }
    1328             :             else
    1329             :             {
    1330           0 :                 if(f_value[idx] == v)
    1331             :                 {
    1332           0 :                     new_value = false;
    1333             :                 }
    1334             :                 else
    1335             :                 {
    1336           0 :                     changed = true;
    1337           0 :                     f_value[idx] = v;
    1338             :                 }
    1339             :             }
    1340           0 :             if(new_value)
    1341             :             {
    1342           0 :                 if(validates(idx))
    1343             :                 {
    1344           0 :                     value_changed(idx);
    1345             :                 }
    1346             :                 else
    1347             :                 {
    1348           0 :                     r = false;
    1349             :                 }
    1350             :             }
    1351           0 :         }
    1352           0 :         if(!changed)
    1353             :         {
    1354           0 :             return true;
    1355             :         }
    1356             :     }
    1357             : 
    1358         665 :     return r;
    1359             : }
    1360             : 
    1361             : 
    1362             : /** \brief Set a multi-value at once.
    1363             :  *
    1364             :  * This function views the \p value parameter as a multi-value parameter
    1365             :  * which it breaks down in multiple parameters and add the results to this
    1366             :  * option_info object as the current value(s).
    1367             :  *
    1368             :  * To separate the values, the function makes use of the separators as
    1369             :  * set by one the set_multiple_separators() functions.
    1370             :  *
    1371             :  * The resulting values must not be the empty string. Empty strings are
    1372             :  * ignored. So if the separator is a comma and you write:
    1373             :  *
    1374             :  * \code
    1375             :  *     foo,,,bar
    1376             :  * \endcode
    1377             :  *
    1378             :  * The result includes "foo" and "bar" and no empty strings.
    1379             :  *
    1380             :  * The value can be quoted in which case it can include any of the
    1381             :  * separators.
    1382             :  *
    1383             :  * \code
    1384             :  *     "foo, bar",'bar, foo'
    1385             :  * \endcode
    1386             :  *
    1387             :  * The result includes "foo, bar" and "bar, foo" (without the quotes
    1388             :  * which get removed in the process).
    1389             :  *
    1390             :  * \note
    1391             :  * The function has the side effect of clearing any existing parameters
    1392             :  * first. So only the newly defined parameters in \p value will be set
    1393             :  * in the option once the function returns.
    1394             :  *
    1395             :  * \param[in] value  The multi-value to save in this option.
    1396             :  * \param[in] option_keys  The keys to which the values are applied.
    1397             :  * \param[in] source  Where the value comes from.
    1398             :  *
    1399             :  * \return true if all the values in \p value were considered valid.
    1400             :  *
    1401             :  * \sa add_value()
    1402             :  * \sa set_value()
    1403             :  */
    1404          38 : bool option_info::set_multiple_values(
    1405             :       std::string const & value
    1406             :     , string_list_t const & option_keys
    1407             :     , option_source_t source)
    1408             : {
    1409          38 :     if(!has_flag(GETOPT_FLAG_ARRAY)
    1410          38 :     && option_keys.size() != 0)
    1411             :     {
    1412           0 :         throw getopt_logic_error(
    1413             :                  "option_info::set_multiple_value(): parameter --"
    1414           0 :                + f_name
    1415           0 :                + " does not support array keys.");
    1416             :     }
    1417             : 
    1418          38 :     if(source == option_source_t::SOURCE_UNDEFINED)
    1419             :     {
    1420           2 :         throw getopt_logic_error(
    1421             :                   "option_info::set_multiple_values(): called with SOURCE_UNDEFINED ("
    1422           2 :                 + std::to_string(static_cast<int>(source))
    1423           5 :                 + ").");
    1424             :     }
    1425             : 
    1426          37 :     string_list_t result;
    1427          37 :     split_string(unquote(value, "[]"), result, f_multiple_separators);
    1428             : 
    1429          37 :     if(!has_flag(GETOPT_FLAG_MULTIPLE)
    1430          37 :     && result.size() > 1)
    1431             :     {
    1432           2 :         throw getopt_logic_error(
    1433             :                  "option_info::set_multiple_value(): parameter --"
    1434           2 :                + f_name
    1435           5 :                + " expects zero or one parameter. The set_multiple_value() function should not be called with parameters that only accept one value.");
    1436             :     }
    1437             : 
    1438          36 :     if(!option_keys.empty())
    1439             :     {
    1440           0 :         string_list_t keyed_result;
    1441           0 :         for(auto const & k : option_keys)
    1442             :         {
    1443           0 :             for(auto & r : result)
    1444             :             {
    1445             :                 // note: the keys are expected to already include the ending ':'
    1446             :                 //
    1447           0 :                 keyed_result.push_back(k + r);
    1448             :             }
    1449             :         }
    1450           0 :         result.swap(keyed_result);
    1451           0 :     }
    1452             : 
    1453          36 :     f_source = source;
    1454          36 :     f_value.swap(result);
    1455          36 :     f_integer.clear();
    1456          36 :     f_double.clear();
    1457             : 
    1458          36 :     bool const r(validate_all_values());
    1459             : 
    1460          36 :     if(f_value != result)
    1461             :     {
    1462             :         // TBD: should we not call this function with all instances?
    1463             :         //      i.e. for(int idx(0); idx < f_value.size(); ++idx) ...
    1464             :         //      and check each value in f_value with the old value in
    1465             :         //      the result variable (knowing that result may be smaller)
    1466             :         //
    1467          34 :         value_changed(0);
    1468             :     }
    1469             : 
    1470          36 :     return r;
    1471          37 : }
    1472             : 
    1473             : 
    1474             : /** \brief Validate all the values of this option_info object.
    1475             :  *
    1476             :  * Whenever you change the validator of an option_info, or change
    1477             :  * all the values with set_multiple_value(), all the values get
    1478             :  * verified using this function. The function removes any value
    1479             :  * which does not validate according to the current validator.
    1480             :  *
    1481             :  * \note
    1482             :  * Keep in mind that an empty value is always considered valid,
    1483             :  * no matter what the validator is. This is because when you
    1484             :  * use an option without a value (i.e. `--order` instead of
    1485             :  * `--order asc`) the value is set to the empty string unless
    1486             :  * there is a default. This allows you to know that the
    1487             :  * option was used without a value, which is useful for some
    1488             :  * options.
    1489             :  *
    1490             :  * \return true if all the values were considered valid.
    1491             :  */
    1492          85 : bool option_info::validate_all_values()
    1493             : {
    1494          85 :     bool all_valid(true);
    1495          85 :     if(f_validator != nullptr)
    1496             :     {
    1497          47 :         for(size_t idx(0); idx < f_value.size(); )
    1498             :         {
    1499          18 :             if(!validates(idx))
    1500             :             {
    1501             :                 // the value was removed, so do not increment `idx`
    1502             :                 //
    1503           9 :                 all_valid = false;
    1504             :             }
    1505             :             else
    1506             :             {
    1507           9 :                 ++idx;
    1508             :             }
    1509             :         }
    1510             :     }
    1511             : 
    1512          85 :     return all_valid;
    1513             : }
    1514             : 
    1515             : 
    1516             : /** \brief Check whether a value is defined.
    1517             :  *
    1518             :  * When parsing the options on the command line or a configuration file,
    1519             :  * values get added to the various existing option_info. If a special
    1520             :  * "*" option is also defined, then any value found on the command line
    1521             :  * or the configuration file are returned.
    1522             :  *
    1523             :  * To know whether this or that option was defined with a value, use
    1524             :  * this function. Even an option which doesn't come with a parameter
    1525             :  * will get an is_defined() returning true once it was found on the
    1526             :  * command line. The value will be the empty string.
    1527             :  *
    1528             :  * \return true if that option was found on the command line, in the
    1529             :  *         environment variable, or in the configuration file.
    1530             :  */
    1531        2854 : bool option_info::is_defined() const
    1532             : {
    1533        2854 :     return !f_value.empty();
    1534             : }
    1535             : 
    1536             : 
    1537             : /** \brief Return the source of this option info.
    1538             :  *
    1539             :  * This function returns the source of this option, i.e. whether it came
    1540             :  * from the command line, the environment variable, a configuration file,
    1541             :  * or some other source that you can define.
    1542             :  *
    1543             :  * The source is similar to a priority in the sense that a source with a
    1544             :  * higher number cannot overwrite the value of a smaller source. The source
    1545             :  * is set at the same time as you set the option. The mechanism may not be
    1546             :  * working exactly as expected when trying to add options from different
    1547             :  * sources.
    1548             :  *
    1549             :  * \note
    1550             :  * In the old version, the value would be the value set with the last
    1551             :  * set_value() command. That worked because we did not try to support
    1552             :  * fully dynamic options. Now we want to have the ability to set an
    1553             :  * option on the command line and that has to prevent the set from
    1554             :  * a dynamic source. Since the dynamic source would do the set_value()
    1555             :  * at a later time, just the order is not enough to know whether the
    1556             :  * dynamic source has permission to overwrite that value.
    1557             :  *
    1558             :  * \return The source of the option info.
    1559             :  */
    1560           5 : option_source_t option_info::source() const
    1561             : {
    1562           5 :     return f_source;
    1563             : }
    1564             : 
    1565             : 
    1566             : /** \brief Whether the sources should be traced.
    1567             :  *
    1568             :  * This is a global flag that you can set before calling any getopt functions
    1569             :  * so that way you can make sure that you get a full trace of all the
    1570             :  * sources for all your options. Then you can use the --show-sources
    1571             :  * command line options to see the resulting data.
    1572             :  *
    1573             :  * \note
    1574             :  * This option is costly since it saves a lot of data, which is why we have
    1575             :  * it as an option. If the getopt() function detects in the argv passed to
    1576             :  * it a "--show-sources" option, then it will automatically call this
    1577             :  * function with true, even before it starts parsing anything. The flag is
    1578             :  * false by default.
    1579             :  *
    1580             :  * \param[in] trace  Whether the sources should be traced.
    1581             :  */
    1582           1 : void option_info::set_trace_sources(bool trace)
    1583             : {
    1584           1 :     g_trace_sources = trace;
    1585           1 : }
    1586             : 
    1587             : 
    1588             : /** \brief Get the trace of this option.
    1589             :  *
    1590             :  * An option can be marked for tracing. This allows you to see exactly
    1591             :  * which value came from which source. We currently support multiple
    1592             :  * sources such as the command line, environment variable, direct,
    1593             :  * dynamic, configuration files.
    1594             :  *
    1595             :  * \return An array of strings representing the source of each value
    1596             :  * in the order they were set in this option_info.
    1597             :  */
    1598          96 : string_list_t const & option_info::trace_sources() const
    1599             : {
    1600          96 :     return f_trace_sources;
    1601             : }
    1602             : 
    1603             : 
    1604             : /** \brief Save the filename of the current configuration file.
    1605             :  *
    1606             :  * While parsing a configuration file, this function gets called to
    1607             :  * set the name which is used to generate the trace of the source
    1608             :  * of all the configuration data.
    1609             :  */
    1610         583 : void option_info::set_configuration_filename(std::string const & filename)
    1611             : {
    1612         583 :     g_configuration_filename = filename;
    1613         583 : }
    1614             : 
    1615             : 
    1616             : /** \brief Retrieve the number of values defined for this option.
    1617             :  *
    1618             :  * This function returns the number of values that were found for this
    1619             :  * option.
    1620             :  *
    1621             :  * If the option is marked as GETOPT_FLAG_MULTIPLE, then this function
    1622             :  * may return 0 or more. Without that flag, this function only returns
    1623             :  * 0 or 1.
    1624             :  *
    1625             :  * You must use the size() parameter to know how many items are defined
    1626             :  * and call the get_value() with a correct `idx` parameter (i.e. a value
    1627             :  * between 0 and `size() - 1`.)
    1628             :  *
    1629             :  * \return The number of values defined in this option.
    1630             :  */
    1631         517 : size_t option_info::size() const
    1632             : {
    1633         517 :     return f_value.size();
    1634             : }
    1635             : 
    1636             : 
    1637             : /** \brief Retrieve the value.
    1638             :  *
    1639             :  * This function returns the value for this option. By default, set the
    1640             :  * \p idx parameter to zero.
    1641             :  *
    1642             :  * The number of values is defined by the size() function.
    1643             :  *
    1644             :  * The is_defined() function returns true if at least one value is defined.
    1645             :  * It is a good idea to check first otherwise you will get an exception.
    1646             :  *
    1647             :  * If the parameter is marked as one that can be processed through the
    1648             :  * variables::process_value() function and the variables were defined
    1649             :  * with set_variables(), then the value will be processed for variables
    1650             :  * unless you set the \p raw parameter to true.
    1651             :  *
    1652             :  * \exception getopt_exception_undefined
    1653             :  * If the \p idx parameter is too large or no value was found for this
    1654             :  * option, then this function raises an invalid error.
    1655             :  *
    1656             :  * \param[in] idx  The index of the parameter to retrieve.
    1657             :  * \param[in] raw  Whether to allow the variable processing or not.
    1658             :  *
    1659             :  * \return The value at \p idx.
    1660             :  */
    1661        1382 : std::string option_info::get_value(int idx, bool raw) const
    1662             : {
    1663        1382 :     if(static_cast<size_t>(idx) >= f_value.size())
    1664             :     {
    1665           4 :         throw getopt_undefined(
    1666             :                       "option_info::get_value(): no value at index "
    1667           4 :                     + std::to_string(idx)
    1668           6 :                     + " (idx >= "
    1669           8 :                     + std::to_string(f_value.size())
    1670           6 :                     + ") for --"
    1671           6 :                     + f_name
    1672          10 :                     + " so you can't get this value.");
    1673             :     }
    1674             : 
    1675        2760 :     if(!raw
    1676        1380 :     && f_variables != nullptr
    1677        2760 :     && has_flag(GETOPT_FLAG_PROCESS_VARIABLES))
    1678             :     {
    1679           6 :         return f_variables->process_value(f_value[idx]);
    1680             :     }
    1681             :     else
    1682             :     {
    1683        1374 :         return f_value[idx];
    1684             :     }
    1685             : }
    1686             : 
    1687             : 
    1688             : /** \brief Get the index at which a value with the given key is defined.
    1689             :  *
    1690             :  * This function searches a value with the specified \p key and return
    1691             :  * the index where it was found.
    1692             :  *
    1693             :  * If the function does not find a value starting with \p key, then it
    1694             :  * returns -1.
    1695             :  *
    1696             :  * The function can be called with the start \p idx set to a value other
    1697             :  * than zero in which case the search starts at that index. It is valid
    1698             :  * to call the function with \p idx larger or equal to the number of
    1699             :  * values defined.
    1700             :  *
    1701             :  * \exception getopt_logic_error
    1702             :  * If the \p idx parameter is negative, this exception is raised.
    1703             :  *
    1704             :  * \exception getopt_undefined
    1705             :  * If no values were defined, this exception is raised. To avoid receiving
    1706             :  * the exception, make sure to first test with is_defined(). Note that if
    1707             :  * the requested key is not found, the function simply returns an empty
    1708             :  * string opposed to raising an exception.
    1709             :  *
    1710             :  * \param[in] key  The key to search for.
    1711             :  * \param[in] idx  Start from this index.
    1712             :  *
    1713             :  * \return The index at which that value is defined or -1 when not found.
    1714             :  */
    1715           0 : int option_info::find_value_index_by_key(std::string key, int idx) const
    1716             : {
    1717           0 :     if(idx < 0)
    1718             :     {
    1719           0 :         throw getopt_logic_error("idx cannot be negative in find_value_index_by_key()");
    1720             :     }
    1721           0 :     if(f_value.empty())
    1722             :     {
    1723           0 :         throw getopt_undefined(
    1724             :                       "option_info::find_value_index_by_key(): --"
    1725           0 :                     + f_name
    1726           0 :                     + " has no values defined.");
    1727             :     }
    1728             : 
    1729           0 :     if(key.back() != ':')
    1730             :     {
    1731           0 :         key += ':';
    1732             :     }
    1733           0 :     int const max(f_value.size());
    1734           0 :     for(; idx < max; ++idx)
    1735             :     {
    1736           0 :         if(f_value[idx].rfind(key, 0) == 0)
    1737             :         {
    1738           0 :             return idx;
    1739             :         }
    1740             :     }
    1741             : 
    1742           0 :     return -1;
    1743             : }
    1744             : 
    1745             : 
    1746             : /** \brief Get the value as a long.
    1747             :  *
    1748             :  * This function returns the value converted to a `long`.
    1749             :  *
    1750             :  * If the value does not represent a valid long value, an error is
    1751             :  * emitted through the logger.
    1752             :  *
    1753             :  * The value will be parsed through the variables if defined and this
    1754             :  * parameter allows it. This means the value may be a variable reference
    1755             :  * instead of an actually value (i.e. `${one}`)
    1756             :  *
    1757             :  * \note
    1758             :  * The function will transform all the values in case this is a
    1759             :  * GETOPT_FLAG_MULTIPLE option and cache the results.
    1760             :  * Calling the function many times with the same index is very fast
    1761             :  * after the first time.
    1762             :  *
    1763             :  * \exception getopt_exception_undefined
    1764             :  * If the value was not defined, the function raises this exception.
    1765             :  *
    1766             :  * \param[in] idx  The index of the value to retrieve as a long.
    1767             :  *
    1768             :  * \return The value at \p idx converted to a long or -1 on error.
    1769             :  */
    1770         157 : long option_info::get_long(int idx) const
    1771             : {
    1772         157 :     if(static_cast<size_t>(idx) >= f_value.size())
    1773             :     {
    1774           2 :         throw getopt_undefined(
    1775             :                       "option_info::get_long(): no value at index "
    1776           2 :                     + std::to_string(idx)
    1777           3 :                     + " (idx >= "
    1778           4 :                     + std::to_string(f_value.size())
    1779           3 :                     + ") for --"
    1780           3 :                     + f_name
    1781           5 :                     + " so you can't get this value.");
    1782             :     }
    1783             : 
    1784             :     // since we may change the f_integer vector between threads,
    1785             :     // add protection (i.e. most everything else is created at the
    1786             :     // beginning so in the main thread)
    1787             :     //
    1788         156 :     cppthread::guard lock(get_global_mutex());
    1789             : 
    1790         156 :     if(f_integer.size() != f_value.size())
    1791             :     {
    1792             :         // we did not yet convert to integers do that now
    1793             :         //
    1794          88 :         size_t const max(f_value.size());
    1795         180 :         for(size_t i(f_integer.size()); i < max; ++i)
    1796             :         {
    1797         102 :             std::int64_t v;
    1798         102 :             if(!validator_integer::convert_string(get_value(i), v))
    1799             :             {
    1800          10 :                 f_integer.clear();
    1801             : 
    1802          20 :                 cppthread::log << cppthread::log_level_t::error
    1803          10 :                                << "invalid number ("
    1804          10 :                                << f_value[i]
    1805          10 :                                << ") in parameter --"
    1806          10 :                                << f_name
    1807          10 :                                << " at offset "
    1808          10 :                                << i
    1809          10 :                                << "."
    1810          20 :                                << cppthread::end;
    1811          10 :                 return -1;
    1812             :             }
    1813          92 :             f_integer.push_back(v);
    1814             :         }
    1815             :     }
    1816             : 
    1817         146 :     return f_integer[idx];
    1818         156 : }
    1819             : 
    1820             : 
    1821             : /** \brief Get the value as a double.
    1822             :  *
    1823             :  * This function returns the value converted to a `double`.
    1824             :  *
    1825             :  * If the value does not represent a valid double value, an error is
    1826             :  * emitted through the logger.
    1827             :  *
    1828             :  * The value will be parsed through the variables if defined and this
    1829             :  * parameter allows it. This means the value may be a variable reference
    1830             :  * instead of an actually value (i.e. `${pi}`)
    1831             :  *
    1832             :  * \note
    1833             :  * The function will transform all the values in case this is a
    1834             :  * GETOPT_FLAG_MULTIPLE option and cache the results.
    1835             :  * Calling the function many times with the same index is very fast
    1836             :  * after the first time.
    1837             :  *
    1838             :  * \exception getopt_exception_undefined
    1839             :  * If the value was not defined, the function raises this exception.
    1840             :  *
    1841             :  * \param[in] idx  The index of the value to retrieve as a double.
    1842             :  *
    1843             :  * \return The value at \p idx converted to a double or -1.0 on error.
    1844             :  */
    1845          68 : double option_info::get_double(int idx) const
    1846             : {
    1847          68 :     if(static_cast<size_t>(idx) >= f_value.size())
    1848             :     {
    1849           2 :         throw getopt_undefined(
    1850             :                       "option_info::get_double(): no value at index "
    1851           2 :                     + std::to_string(idx)
    1852           3 :                     + " (idx >= "
    1853           4 :                     + std::to_string(f_value.size())
    1854           3 :                     + ") for --"
    1855           3 :                     + f_name
    1856           5 :                     + " so you can't get this value.");
    1857             :     }
    1858             : 
    1859             :     // since we may change the f_integer vector between threads,
    1860             :     // add protection (i.e. most everything else is created at the
    1861             :     // beginning so in the main thread)
    1862             :     //
    1863          67 :     cppthread::guard lock(get_global_mutex());
    1864             : 
    1865          67 :     if(f_double.size() != f_value.size())
    1866             :     {
    1867             :         // we did not yet convert to doubles do that now
    1868             :         //
    1869          33 :         size_t const max(f_value.size());
    1870          65 :         for(size_t i(f_double.size()); i < max; ++i)
    1871             :         {
    1872          33 :             double v;
    1873          33 :             if(!validator_double::convert_string(get_value(i), v))
    1874             :             {
    1875           1 :                 f_double.clear();
    1876             : 
    1877           2 :                 cppthread::log << cppthread::log_level_t::error
    1878           1 :                                << "invalid number ("
    1879           1 :                                << f_value[i]
    1880           1 :                                << ") in parameter --"
    1881           1 :                                << f_name
    1882           1 :                                << " at offset "
    1883           1 :                                << i
    1884           1 :                                << "."
    1885           2 :                                << cppthread::end;
    1886           1 :                 return -1;
    1887             :             }
    1888          32 :             f_double.push_back(v);
    1889             :         }
    1890             :     }
    1891             : 
    1892          66 :     return f_double[idx];
    1893          67 : }
    1894             : 
    1895             : 
    1896             : /** \brief Lock this value.
    1897             :  *
    1898             :  * This function allows for locking a value so further reading of data
    1899             :  * from different sources will not overwrite it.
    1900             :  *
    1901             :  * When parsing the data we have multiple levels. Here are these levels
    1902             :  * in priority order (first option found is the one we keep):
    1903             :  *
    1904             :  * \li Command line options
    1905             :  * \li Environment Variables
    1906             :  * \li Configuration File: Local (`./\<name>.conf`)
    1907             :  * \li Configuration File: User's (`~/.config/\<proc>/\<name>.conf`)
    1908             :  * \li Configuration File: Project sub-folder (`/etc/\<proc>/\<proc>.d/\<ohter-name>.conf`)
    1909             :  * \li Configuration File: Project folder (`/etc/\<proc>/\<other-name>.conf`)
    1910             :  * \li Configuration File: System sub-folder (`/etc/\<proc>/\<name>.conf`)
    1911             :  * \li Configuration File: System folder (`/etc/\<proc>/\<name>.conf`)
    1912             :  *
    1913             :  * \note
    1914             :  * Most of our packages do not have a Project and a System set of
    1915             :  * configuration files. Often they will have just the System files.
    1916             :  *
    1917             :  * We use this lock because we want to support multiple values so just
    1918             :  * detecting that a value is set to not add more options is not a good
    1919             :  * test. Instead we lock the values that are set before moving to the
    1920             :  * next level.
    1921             :  *
    1922             :  * \param[in] always  Always lock that option, whether it is defined or not.
    1923             :  */
    1924           6 : void option_info::lock(bool always)
    1925             : {
    1926           6 :     if(!always)
    1927             :     {
    1928           4 :         if(!is_defined())
    1929             :         {
    1930           2 :             return;
    1931             :         }
    1932             :     }
    1933             : 
    1934           4 :     add_flag(GETOPT_FLAG_LOCK);
    1935             : }
    1936             : 
    1937             : 
    1938             : /** \brief Unlock this value.
    1939             :  *
    1940             :  * This function does the opposite of the lock() function. It allows for
    1941             :  * the value to be updated again.
    1942             :  *
    1943             :  * Once the getpot object is done parsing all the input, it unlocks all
    1944             :  * the values using this function. The unlock is always unconditional.
    1945             :  */
    1946           4 : void option_info::unlock()
    1947             : {
    1948           4 :     remove_flag(GETOPT_FLAG_LOCK);
    1949           4 : }
    1950             : 
    1951             : 
    1952             : /** \brief Reset this value.
    1953             :  *
    1954             :  * This function clears the value so it is marked as undefined again.
    1955             :  *
    1956             :  * To reuse the same getopt object multiple times, you can use the
    1957             :  * reset() function which clears the values. Then you can parse a
    1958             :  * new set of argc/argv parameters.
    1959             :  */
    1960          27 : void option_info::reset()
    1961             : {
    1962          27 :     if(is_defined())
    1963             :     {
    1964          23 :         f_source = option_source_t::SOURCE_UNDEFINED;
    1965          23 :         f_value.clear();
    1966          23 :         f_integer.clear();
    1967          23 :         f_double.clear();
    1968             : 
    1969          23 :         value_changed(0);
    1970             :     }
    1971          27 : }
    1972             : 
    1973             : 
    1974             : /** \brief Add a callback to call on a change to this value.
    1975             :  *
    1976             :  * Since we now officially support dynamically setting option values, we
    1977             :  * decided to add a callback mechanism that lets you know that an option
    1978             :  * changed. That way you can react to the change as soon as possible instead
    1979             :  * of having to poll for the value once in a while.
    1980             :  *
    1981             :  * \param[in] c  The callback. Usually an std::bind() call.
    1982             :  *
    1983             :  * \return The new callback identifier.
    1984             :  */
    1985           2 : option_info::callback_id_t option_info::add_callback(callback_t const & c)
    1986             : {
    1987           2 :     cppthread::guard lock(get_global_mutex());
    1988             : 
    1989           2 :     ++f_next_callback_id;
    1990           2 :     f_callbacks.emplace_back(f_next_callback_id, c);
    1991           2 :     return f_next_callback_id;
    1992           2 : }
    1993             : 
    1994             : 
    1995             : /** \brief Remove a callback.
    1996             :  *
    1997             :  * This function is the opposite of the add_callback(). It removes a callback
    1998             :  * that you previously added. This is useful if you are interested in hearing
    1999             :  * about the value when set but are not interested at all about future
    2000             :  * changes.
    2001             :  *
    2002             :  * \param[in] id  The id returned by the add_callback() function.
    2003             :  */
    2004           3 : void option_info::remove_callback(callback_id_t id)
    2005             : {
    2006           3 :     cppthread::guard lock(get_global_mutex());
    2007             : 
    2008           3 :     auto it(std::find_if(
    2009             :               f_callbacks.begin()
    2010             :             , f_callbacks.end()
    2011           4 :             , [id](auto e)
    2012             :             {
    2013           4 :                 return e.f_id == id;
    2014             :             }));
    2015           3 :     if(it != f_callbacks.end())
    2016             :     {
    2017           2 :         f_callbacks.erase(it);
    2018             :     }
    2019           6 : }
    2020             : 
    2021             : 
    2022             : /** \brief Call whenever the value changed so we can handle callbacks.
    2023             :  *
    2024             :  * This function is called on a change of the internal values.
    2025             :  *
    2026             :  * The function is used to call the callbacks that were added to this
    2027             :  * option_info object. The function first copies the existing list of
    2028             :  * callbacks so you can safely update the list from within a callback.
    2029             :  *
    2030             :  * \warning
    2031             :  * Destroying your advgetopt::getopt option is not safe while a callback
    2032             :  * is running.
    2033             :  *
    2034             :  * \param[in] idx  This represents the index of the value that last changed
    2035             :  * (currently poor attempt to fix this issue).
    2036             :  */
    2037         716 : void option_info::value_changed(int idx)
    2038             : {
    2039         716 :     trace_source(idx);
    2040             : 
    2041         716 :     callback_vector_t callbacks;
    2042         716 :     callbacks.reserve(f_callbacks.size());
    2043             : 
    2044             :     {
    2045         716 :         cppthread::guard lock(get_global_mutex());
    2046         716 :         callbacks = f_callbacks;
    2047         716 :     }
    2048             : 
    2049         722 :     for(auto e : callbacks)
    2050             :     {
    2051           6 :         e.f_callback(*this);
    2052           6 :     }
    2053        1432 : }
    2054             : 
    2055             : 
    2056             : 
    2057             : /** \brief Remember the source information at of this last change.
    2058             :  *
    2059             :  * The getopt class supports a flag which turns on the trace mode. This
    2060             :  * allows it to memorize where the values came fram. This includes the
    2061             :  * source and if the source is a configuration file, the path to that
    2062             :  * configuration file.
    2063             :  */
    2064         716 : void option_info::trace_source(int idx)
    2065             : {
    2066         716 :     if(!g_trace_sources)
    2067             :     {
    2068         563 :         return;
    2069             :     }
    2070             : 
    2071         153 :     std::string s;
    2072         153 :     switch(f_source)
    2073             :     {
    2074          93 :     case option_source_t::SOURCE_COMMAND_LINE:
    2075          93 :         s = "command-line";
    2076          93 :         break;
    2077             : 
    2078          38 :     case option_source_t::SOURCE_CONFIGURATION:
    2079          38 :         s = "configuration=\"" + g_configuration_filename + "\"";
    2080          38 :         break;
    2081             : 
    2082           1 :     case option_source_t::SOURCE_DIRECT:
    2083           1 :         s = "direct";
    2084           1 :         break;
    2085             : 
    2086           1 :     case option_source_t::SOURCE_DYNAMIC:
    2087           1 :         s = "dynamic";
    2088           1 :         break;
    2089             : 
    2090          19 :     case option_source_t::SOURCE_ENVIRONMENT_VARIABLE:
    2091          19 :         s = "environment-variable";
    2092          19 :         break;
    2093             : 
    2094           1 :     case option_source_t::SOURCE_UNDEFINED:
    2095             :         // this happens on a reset or all the values were invalid
    2096             :         //
    2097           1 :         f_trace_sources.push_back(f_name + " [*undefined-source*]");
    2098           1 :         return;
    2099             : 
    2100             :     }
    2101             : 
    2102         152 :     if(f_value.empty())
    2103             :     {
    2104             :         // this should never ever happen
    2105             :         // (if f_value is empty then f_source == SOURCE_UNDEFINED)
    2106             :         //
    2107             :         f_trace_sources.push_back(f_name + " [*undefined-value*]");     // LCOV_EXCL_LINE
    2108             :     }
    2109             :     else
    2110             :     {
    2111             :         // TODO: change the algorithm, if the option supports
    2112             :         //
    2113         152 :         if(!has_flag(GETOPT_FLAG_MULTIPLE)
    2114         152 :         || static_cast<std::size_t>(idx) >= f_value.size())
    2115             :         {
    2116         128 :             f_trace_sources.push_back(f_name + "=" + f_value[0] + " [" + s + "]");
    2117             :         }
    2118             :         else
    2119             :         {
    2120          24 :             f_trace_sources.push_back(f_name + "[" + std::to_string(idx) + "]=" + f_value[idx] + " [" + s + "]");
    2121             :         }
    2122             :     }
    2123         153 : }
    2124             : 
    2125             : 
    2126             : }   // namespace advgetopt
    2127             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14

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