LCOV - code coverage report
Current view: top level - advgetopt - advgetopt_data.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 149 149 100.0 %
Date: 2019-08-10 16:09:07 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * License:
       3             :  *    Copyright (c) 2006-2019  Made to Order Software Corp.  All Rights Reserved
       4             :  *
       5             :  *    https://snapwebsites.org/
       6             :  *    contact@m2osw.com
       7             :  *
       8             :  *    This program is free software; you can redistribute it and/or modify
       9             :  *    it under the terms of the GNU General Public License as published by
      10             :  *    the Free Software Foundation; either version 2 of the License, or
      11             :  *    (at your option) any later version.
      12             :  *
      13             :  *    This program is distributed in the hope that it will be useful,
      14             :  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  *    GNU General Public License for more details.
      17             :  *
      18             :  *    You should have received a copy of the GNU General Public License along
      19             :  *    with this program; if not, write to the Free Software Foundation, Inc.,
      20             :  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      21             :  *
      22             :  * Authors:
      23             :  *    Alexis Wilke   alexis@m2osw.com
      24             :  *    Doug Barbieri  doug@m2osw.com
      25             :  */
      26             : 
      27             : /** \file
      28             :  * \brief Advanced getopt data access implementation.
      29             :  *
      30             :  * The advgetopt class has many function used to access the data in the
      31             :  * class. These functions are gathered here.
      32             :  */
      33             : 
      34             : // self
      35             : //
      36             : #include    "advgetopt/advgetopt.h"
      37             : 
      38             : // advgetopt lib
      39             : //
      40             : #include    "advgetopt/conf_file.h"
      41             : #include    "advgetopt/exception.h"
      42             : #include    "advgetopt/log.h"
      43             : 
      44             : 
      45             : // last include
      46             : //
      47             : #include <snapdev/poison.h>
      48             : 
      49             : 
      50             : 
      51             : 
      52             : namespace advgetopt
      53             : {
      54             : 
      55             : 
      56             : 
      57             : 
      58             : 
      59             : /** \brief Check whether a parameter is defined.
      60             :  *
      61             :  * This function returns true if the specified parameter is found as part of
      62             :  * the command line options.
      63             :  *
      64             :  * You must specify the long name of the option. So a `--verbose` option can
      65             :  * be checked with:
      66             :  *
      67             :  * \code
      68             :  *   if(is_defined("verbose")) ...
      69             :  * \endcode
      70             :  *
      71             :  * For options that come with a short name, you may also specify the short
      72             :  * name. This is done with a string in this case. It can be a UTF-8
      73             :  * character. The short name is used if the string represents exactly one
      74             :  * Unicode character. So the following is equivalent to the previous
      75             :  * example, assuming your verbose definition has `v` as the short name:
      76             :  *
      77             :  * \code
      78             :  *   if(is_defined("v")) ...
      79             :  * \endcode
      80             :  *
      81             :  * \note
      82             :  * This function returns true when the option was found on the command line,
      83             :  * the environment variable, or a configuration file. It returns false if
      84             :  * the option is defined, but was not specified anywhere by the client using
      85             :  * your program. Also, specifying the option in one of those three locations
      86             :  * when not allowed at that location will not result in this flag being raised.
      87             :  *
      88             :  * \param[in] name  The long name or short name of the option to check.
      89             :  *
      90             :  * \return true if the option was defined in a configuration file, the
      91             :  *         environment variable, or the command line.
      92             :  */
      93        1028 : bool getopt::is_defined(std::string const & name) const
      94             : {
      95        2056 :     option_info::pointer_t opt(get_option(name));
      96        1028 :     if(opt != nullptr)
      97             :     {
      98         717 :         return opt->is_defined();
      99             :     }
     100             : 
     101         311 :     return false;
     102             : }
     103             : 
     104             : 
     105             : /** \brief Retrieve the number of arguments.
     106             :  *
     107             :  * This function returns the number of arguments that were specified after
     108             :  * the named option.
     109             :  *
     110             :  * The function returns zero if the argument was never specified on the
     111             :  * command line. If the option accepts exactly one parameter (i.e. not
     112             :  * marked as a multiple arguments option: GETOPT_FLAG_MULTIPLE) then
     113             :  * the function returns either zero (not specified) or one (specified
     114             :  * at least once.)
     115             :  *
     116             :  * \param[in] name  The name of the option to check.
     117             :  *
     118             :  * \return The number of arguments specified on the command line or zero.
     119             :  */
     120         620 : size_t getopt::size(std::string const & name) const
     121             : {
     122        1240 :     option_info::pointer_t opt(get_option(name));
     123         620 :     if(opt != nullptr)
     124             :     {
     125         393 :         return opt->size();
     126             :     }
     127         227 :     return 0;
     128             : }
     129             : 
     130             : 
     131             : /** \brief Check whether an option has a default value.
     132             :  *
     133             :  * Some parameters may be given a default. This function is used to
     134             :  * detect whether such a default value is defined.
     135             :  *
     136             :  * \note
     137             :  * This function is particularly useful in the event the default value
     138             :  * may be an empty string.
     139             :  *
     140             :  * \exception getopt_exception_undefined
     141             :  * The getopt_exception_undefined exception is raised if this function is
     142             :  * called with an empty \p name.
     143             :  *
     144             :  * \param[in] name  The name of the parameter of which you want to know
     145             :  *                  whether it has a default value or not.
     146             :  *
     147             :  * \return true if the default value was defined (even if an empty string.)
     148             :  */
     149          71 : bool getopt::has_default(std::string const & name) const
     150             : {
     151          71 :     if(name.empty())
     152             :     {
     153           2 :         throw getopt_exception_logic("argument name cannot be empty.");
     154             :     }
     155             : 
     156         138 :     option_info::pointer_t opt(get_option(name));
     157          69 :     if(opt != nullptr)
     158             :     {
     159          64 :         return opt->has_default();
     160             :     }
     161             : 
     162           5 :     return false;
     163             : }
     164             : 
     165             : 
     166             : /** \brief Get the default value for this option.
     167             :  *
     168             :  * When an option is not defined, you may use this function to retrieve its
     169             :  * default instead. This is actually done automatically when you call the
     170             :  * get_string() or get_long() functions.
     171             :  *
     172             :  * An option without a default has this function returning nullptr.
     173             :  *
     174             :  * \note
     175             :  * Whether an option has a default value should be checked with the
     176             :  * has_default() function which returns true when the default value
     177             :  * was defined. An option with an empty string as the default is
     178             :  * a valid case which cannot be detected otherwise.
     179             :  *
     180             :  * \exception getopt_exception_undefined
     181             :  * The getopt_exception_undefined exception is raised if this function is
     182             :  * called with an empty \p name.
     183             :  *
     184             :  * \param[in] name  The name of the parameter of which you want to retrieve
     185             :  *                  the default value.
     186             :  *
     187             :  * \return The default value or an empty string if no value is defined.
     188             :  */
     189         537 : std::string getopt::get_default(std::string const & name) const
     190             : {
     191         537 :     if(name.empty())
     192             :     {
     193           2 :         throw getopt_exception_logic("argument name cannot be empty.");
     194             :     }
     195             : 
     196        1070 :     option_info::pointer_t opt(get_option(name));
     197         535 :     if(opt != nullptr)
     198             :     {
     199         310 :         return opt->get_default();
     200             :     }
     201             : 
     202         225 :     return std::string();
     203             : }
     204             : 
     205             : 
     206             : /** \brief This function retrieves an argument as a long value.
     207             :  *
     208             :  * This function reads the specified argument from the named option and
     209             :  * transforms it to a long value. It then checks the result against the
     210             :  * specified minimum and maximum range.
     211             :  *
     212             :  * The function name represents an argument that needs to be defined. You
     213             :  * can test whether it was defined on the command line with the is_defined()
     214             :  * function. The index must be between 0 and 'size() - 1' inclusive. If
     215             :  * the item was not defined, then size() returns zero and you cannot call
     216             :  * this function.
     217             :  *
     218             :  * The function does not check the validity of the minimum and maximum
     219             :  * parameters. If \p min \> \p max is true then the function will always
     220             :  * fail with a call to usage() as no value can be defined between \p min
     221             :  * and \p max in that case. The minimum and maximum values are inclusive,
     222             :  * so a range of 1 to 9 is defined with exactly 1 and 9 in min and max.
     223             :  * For example, the z library compression could be retrieved with:
     224             :  *
     225             :  * \code
     226             :  * int level(6); // default to 6
     227             :  * if(opt.is_defined("zlevel"))
     228             :  * {
     229             :  *   zlevel = opt.get_long("zlevel", 0, 1, 9);
     230             :  * }
     231             :  * \endcode
     232             :  *
     233             :  * Note that the function can be used to read unsigned numbers, however
     234             :  * at this point getopt does not really support negative numbers (i.e. because
     235             :  * -\<number> is viewed as an option.)
     236             :  *
     237             :  * \exception getopt_exception_undefined
     238             :  * The getopt_exception_undefined exception is raised if \p name was not
     239             :  * found on the command line and it has no default, or if \p idx is
     240             :  * out of bounds.
     241             :  *
     242             :  * \param[in] name  The name of the option to retrieve.
     243             :  * \param[in] idx  The index of the argument to retrieve.
     244             :  * \param[in] min  The minimum value that will be returned (inclusive).
     245             :  * \param[in] max  The maximum value that will be returned (inclusive).
     246             :  *
     247             :  * \return The argument as a long.
     248             :  */
     249         122 : long getopt::get_long(std::string const & name, int idx, long min, long max)
     250             : {
     251         244 :     option_info::pointer_t opt(get_option(name));
     252         122 :     if(opt == nullptr)
     253             :     {
     254             :         throw getopt_exception_logic(
     255             :                   "there is no --"
     256           6 :                 + name
     257           9 :                 + " option defined.");
     258             :     }
     259             : 
     260         119 :     long result(0);
     261         119 :     if(!opt->is_defined())
     262             :     {
     263          88 :         std::string const d(opt->get_default());
     264          44 :         if(d.empty())
     265             :         {
     266             :             throw getopt_exception_logic(
     267             :                       "the --"
     268          12 :                     + name
     269          18 :                     + " option was not defined on the command line and it has no or an empty default.");
     270             :         }
     271             :         char * end;
     272          38 :         char const * str(d.c_str());
     273          38 :         result = strtol(str, &end, 10);
     274          38 :         if(end != str + d.length())
     275             :         {
     276             :             // here we throw because this default value is defined in the
     277             :             // options of the tool and not by the user
     278             :             //
     279             :             throw getopt_exception_logic(
     280             :                       "invalid default number \""
     281           6 :                     + d
     282           6 :                     + "\" for option --"
     283           9 :                     + name);
     284             :         }
     285             :     }
     286             :     else
     287             :     {
     288          75 :         result = opt->get_long(idx);
     289             :     }
     290             : 
     291             :     // TODO: replace with validators
     292             :     //
     293         110 :     if(result < min || result > max)
     294             :     {
     295           4 :         log << log_level_t::error
     296           2 :             << result
     297           2 :             << " is out of bounds ("
     298           2 :             << min
     299           2 :             << ".."
     300           2 :             << max
     301           2 :             << " inclusive) in parameter --"
     302           2 :             << name
     303           2 :             << "."
     304           2 :             << end;
     305           2 :         result = -1;
     306             :     }
     307             : 
     308         220 :     return result;
     309             : }
     310             : 
     311             : 
     312             : /** \brief Get the content of an option as a string.
     313             :  *
     314             :  * Get the content of the named parameter as a string. Command line options
     315             :  * that accept multiple arguments accept the \p idx parameter to
     316             :  * specify which item you are interested in.
     317             :  *
     318             :  * Note that the option must have been specified on the command line or have
     319             :  * a default value. For options that do not have a default value, you want
     320             :  * to call the is_defined() function first.
     321             :  *
     322             :  * \exception getopt_exception_undefined
     323             :  * The getopt_exception_undefined exception is raised if \p name was not
     324             :  * found on the command line and it has no default, or if \p idx is
     325             :  * out of bounds.
     326             :  *
     327             :  * \param[in] name  The name of the option to read.
     328             :  * \param[in] idx  The zero based index of a multi-argument command line option.
     329             :  *
     330             :  * \return The option argument as a string.
     331             :  */
     332         498 : std::string getopt::get_string(std::string const & name, int idx) const
     333             : {
     334         996 :     option_info::pointer_t opt(get_option(name));
     335         498 :     if(opt == nullptr)
     336             :     {
     337             :         throw getopt_exception_logic(
     338             :                   "there is no --"
     339           6 :                 + name
     340           9 :                 + " option defined.");
     341             :     }
     342             : 
     343         495 :     if(!opt->is_defined())
     344             :     {
     345          41 :         if(opt->has_default())
     346             :         {
     347          36 :             return opt->get_default();
     348             :         }
     349             :         throw getopt_exception_logic(
     350             :                   "the --"
     351          10 :                 + name
     352          15 :                 + " option was not defined on the command line and it has no default.");
     353             :     }
     354             : 
     355         454 :     return opt->get_value(idx);
     356             : }
     357             : 
     358             : 
     359             : /** \brief Retrieve the value of an argument.
     360             :  *
     361             :  * This operator returns the value of an argument just like the get_string()
     362             :  * does when the argument is defined. When the argument is not defined and it
     363             :  * has no default, it returns an empty string instead of throwing.
     364             :  *
     365             :  * The function is only capable of returning the very first value. If this
     366             :  * argument has the GETOPT_FLAG_MULTIPLE flag set, you probably want to use
     367             :  * the get_string() instead.
     368             :  *
     369             :  * \param[in] name  The name of the option to retrieve.
     370             :  *
     371             :  * \return The value of that option or an empty string if not defined.
     372             :  */
     373         193 : std::string getopt::operator [] (std::string const & name) const
     374             : {
     375         193 :     if(name.empty())
     376             :     {
     377           2 :         throw getopt_exception_logic("argument name cannot be empty.");
     378             :     }
     379             : 
     380         382 :     option_info::pointer_t opt(get_option(name));
     381         191 :     if(opt == nullptr)
     382             :     {
     383           1 :         return std::string();
     384             :     }
     385             : 
     386         190 :     if(!opt->is_defined())
     387             :     {
     388           6 :         if(opt->has_default())
     389             :         {
     390           5 :             return opt->get_default();
     391             :         }
     392           1 :         return std::string();
     393             :     }
     394             : 
     395         184 :     return opt->get_value(0);
     396             : }
     397             : 
     398             : 
     399             : /** \brief Access a parameter in read and write mode.
     400             :  *
     401             :  * This function allows you to access an argument which may or may not
     402             :  * yet exist.
     403             :  *
     404             :  * The return value is a reference to that parameter. You can read
     405             :  * and write to the reference.
     406             :  *
     407             :  * A non-existant argument is created only if necessary. That is,
     408             :  * only if you actually use an assignment operator as follow:
     409             :  *
     410             :  * \code
     411             :  *      // straight assignment:
     412             :  *      opt["my-var"] = "123";
     413             :  *
     414             :  *      // or concatenation:
     415             :  *      opt["my-var"] += "append";
     416             :  * \endcode
     417             :  *
     418             :  * In read mode and unless you defined a default, a non-existant argument
     419             :  * is viewed as an empty string or 0 if retrieved as a long:
     420             :  *
     421             :  * \code
     422             :  *      // if non-existant you get an empty string:
     423             :  *      std::string value = opt["non-existant"];
     424             :  *
     425             :  *      // if non-existant you get zero:
     426             :  *      long value = opt["non-existant"].get_long();
     427             :  * \endcode
     428             :  *
     429             :  * The get_long() function may generate an error if the parameter is not
     430             :  * a valid integer. Also when a default is defined, it tries to convert
     431             :  * the default value to a number and if that fails an error is generated.
     432             :  *
     433             :  * \note
     434             :  * This operator only allows you to access the very first value of
     435             :  * this option. If the option is marked with GETOPT_FLAG_MULTIPLE,
     436             :  * you may want to use the get_option() function and then handle
     437             :  * the option multiple values manually with the option_info::get_value()
     438             :  * and option_info::set_value().
     439             :  *
     440             :  * \warning
     441             :  * If the option is an alias and the destination is not defined you
     442             :  * can still get an exception raised.
     443             :  *
     444             :  * \param[in] name  The name of the option to access.
     445             :  *
     446             :  * \return A reference to this option with support for many std::string like
     447             :  *         operators.
     448             :  */
     449         163 : option_info_ref getopt::operator [] (std::string const & name)
     450             : {
     451         163 :     if(name.empty())
     452             :     {
     453           2 :         throw getopt_exception_logic("argument name cannot be empty.");
     454             :     }
     455             : 
     456         322 :     option_info::pointer_t opt(get_option(name));
     457         161 :     if(opt == nullptr)
     458             :     {
     459          54 :         if(name.length() == 1)
     460             :         {
     461           2 :             throw getopt_exception_logic("argument name cannot be one letter if it does not exist in operator [].");
     462             :         }
     463             : 
     464             :         // The option doesn't exist yet, create it
     465             :         //
     466          52 :         opt = std::make_shared<option_info>(name);
     467          52 :         f_options_by_name[name] = opt;
     468             :     }
     469             : 
     470         318 :     return option_info_ref(opt);
     471             : }
     472             : 
     473             : 
     474             : /** \brief Process the system options.
     475             :  *
     476             :  * If you have the GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS flag turned on,
     477             :  * then several options are automatically added to your list of supported
     478             :  * options, such as `--version`.
     479             :  *
     480             :  * This function processes these options if any were used by the client.
     481             :  *
     482             :  * If the function finds one or more system flags as being defined, it
     483             :  * returns a non-zero set of SYSTEM_OPTION_... flags. This can be useful
     484             :  * to decide whether to continue processing or not.
     485             :  *
     486             :  * We define a set of flags that can help you decide whether to continue
     487             :  * or exit. In most cases, we propose that you exit your program if any
     488             :  * one of the options was a command. This is done like so:
     489             :  *
     490             :  * \code
     491             :  * if(process_system_options & SYSTEM_OPTION_COMMANDS_MASK) != 0)
     492             :  * {
     493             :  *     exit(1);
     494             :  * }
     495             :  * \endcode
     496             :  *
     497             :  * You may still want to continue, though, if other flags where set,
     498             :  * even if some commands were used. For example, some tools will print
     499             :  * their version and move forward with there work (i.e. compilers often do
     500             :  * that to help with logging all the information about a build process,
     501             :  * including the version of the compiler.)
     502             :  *
     503             :  * \param[in] out  The stream where output is sent if required.
     504             :  *
     505             :  * \return non-zero set of flags if any of the system parameters were processed.
     506             :  */
     507          28 : flag_t getopt::process_system_options(std::basic_ostream<char> & out)
     508             : {
     509          28 :     flag_t result(SYSTEM_OPTION_NONE);
     510             : 
     511             :     // --version
     512          28 :     if(is_defined("version"))
     513             :     {
     514           2 :         out << f_options_environment.f_version << std::endl;
     515           2 :         result |= SYSTEM_OPTION_VERSION;
     516             :     }
     517             : 
     518             :     // --help
     519          28 :     if(is_defined("help"))
     520             :     {
     521           1 :         out << usage() << std::endl;
     522           1 :         result |= SYSTEM_OPTION_HELP;
     523             :     }
     524             : 
     525             :     // --long-help
     526          28 :     if(is_defined("long-help"))
     527             :     {
     528           1 :         out << usage(GETOPT_FLAG_SHOW_ALL) << std::endl;
     529           1 :         result |= SYSTEM_OPTION_HELP;
     530             :     }
     531             : 
     532          28 :     if(f_options_environment.f_groups != nullptr)
     533             :     {
     534           6 :         for(group_description const * grp = f_options_environment.f_groups
     535           6 :           ; grp->f_group != GETOPT_FLAG_GROUP_NONE
     536             :           ; ++grp)
     537             :         {
     538             :             // the name is not mandatory, without it you do not get the command
     539             :             // line option but still get the group description
     540             :             //
     541           4 :             if(grp->f_name != nullptr
     542           4 :             && *grp->f_name != '\0')
     543             :             {
     544           8 :                 std::string const name(grp->f_name);
     545           8 :                 std::string const option_name(name + "-help");
     546           4 :                 if(is_defined(option_name))
     547             :                 {
     548           2 :                     out << usage(grp->f_group) << std::endl;
     549           2 :                     result |= SYSTEM_OPTION_HELP;
     550             :                 }
     551             :             }
     552             :         }
     553             :     }
     554             : 
     555             :     // --copyright
     556          28 :     if(is_defined("copyright"))
     557             :     {
     558           2 :         out << f_options_environment.f_copyright << std::endl;
     559           2 :         result |= SYSTEM_OPTION_COPYRIGHT;
     560             :     }
     561             : 
     562             :     // --license
     563          28 :     if(is_defined("license"))
     564             :     {
     565           2 :         out << f_options_environment.f_license << std::endl;
     566           2 :         result |= SYSTEM_OPTION_LICENSE;
     567             :     }
     568             : 
     569             :     // --build-date
     570          28 :     if(is_defined("build-date"))
     571             :     {
     572           2 :         out << "Built on "
     573           4 :             << f_options_environment.f_build_date
     574           2 :             << " at "
     575           4 :             << f_options_environment.f_build_time
     576           2 :             << std::endl;
     577           2 :         result |= SYSTEM_OPTION_BUILD_DATE;
     578             :     }
     579             : 
     580             :     // --environment-variable-name
     581          28 :     if(is_defined("environment-variable-name"))
     582             :     {
     583           3 :         if(f_options_environment.f_environment_variable_name == nullptr
     584           2 :         || *f_options_environment.f_environment_variable_name == '\0')
     585             :         {
     586           2 :             out << f_options_environment.f_project_name
     587           2 :                 << " does not support an environment variable."
     588           2 :                 << std::endl;
     589             :         }
     590             :         else
     591             :         {
     592           1 :             out << f_options_environment.f_environment_variable_name << std::endl;
     593             :         }
     594           3 :         result |= SYSTEM_OPTION_ENVIRONMENT_VARIABLE_NAME;
     595             :     }
     596             : 
     597             :     // --configuration-filenames
     598          28 :     if(is_defined("configuration-filenames"))
     599             :     {
     600           6 :         string_list_t list(get_configuration_filenames(false, false));
     601           3 :         if(list.empty())
     602             :         {
     603           1 :             out << f_options_environment.f_project_name
     604           1 :                 << " does not support configuration files."
     605           1 :                 << std::endl;
     606             :         }
     607             :         else
     608             :         {
     609           2 :             out << "Configuration filenames:" << std::endl;
     610          26 :             for(auto n : list)
     611             :             {
     612          24 :                 out << " . " << n << std::endl;
     613             :             }
     614             :         }
     615           3 :         result |= SYSTEM_OPTION_CONFIGURATION_FILENAMES;
     616             :     }
     617             : 
     618             :     // --path-to-option-definitions
     619          28 :     if(is_defined("path-to-option-definitions"))
     620             :     {
     621           2 :         if(f_options_environment.f_options_files_directory == nullptr
     622           1 :         || *f_options_environment.f_options_files_directory == '\0')
     623             :         {
     624           1 :             out << "/usr/share/advgetopt/options" << std::endl;
     625             :         }
     626             :         else
     627             :         {
     628           1 :             out << f_options_environment.f_options_files_directory << std::endl;
     629             :         }
     630           2 :         result |= SYSTEM_OPTION_PATH_TO_OPTION_DEFINITIONS;
     631             :     }
     632             : 
     633             :     // --config-dir
     634          28 :     if(is_defined("config-dir"))
     635             :     {
     636             :         // these are automatically used in the get_configuration_filenames()
     637             :         // function, there is nothing for us to do here
     638             :         //
     639           1 :         result |= SYSTEM_OPTION_CONFIG_DIR;
     640             :     }
     641             : 
     642          28 :     return result;
     643             : }
     644             : 
     645             : 
     646             : 
     647             : 
     648             : 
     649           6 : } // namespace advgetopt
     650             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12