LCOV - code coverage report
Current view: top level - advgetopt - options.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 65 65 100.0 %
Date: 2020-11-13 17:54:34 Functions: 117 117 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             : #pragma once
      27             : 
      28             : /** \file
      29             :  * \brief Definitions of the options class a initialization functions.
      30             :  *
      31             :  * The advgetopt library offers an advanced way to manage your command
      32             :  * line tools options on the command line, in environment variables, and
      33             :  * in configuration files.
      34             :  */
      35             : 
      36             : 
      37             : // advgetopt lib
      38             : //
      39             : #include    "advgetopt/option_info.h"
      40             : 
      41             : 
      42             : // snapdev lib
      43             : //
      44             : #include    <snapdev/not_used.h>
      45             : 
      46             : 
      47             : 
      48             : namespace advgetopt
      49             : {
      50             : 
      51             : 
      52             : 
      53             : 
      54             : 
      55             : 
      56             : // this structure is used to declare your command line options in a
      57             : // constexpr array
      58             : //
      59             : // TODO: plan to transform all the strings in an array with a scheme such
      60             : //       as:
      61             : //
      62             : //          "a:<alias>",
      63             : //          "d:<default>",
      64             : //          "h:<help>",
      65             : //          "n:<name>",
      66             : //          "s:<separator>",
      67             : //          "v:<validator>(<param>, ...)"
      68             : //
      69             : //       our templates should be able to create that array automatically.
      70             : //       This way we avoid many nullptr in so many definitions (i.e. most
      71             : //       our definitions do not have a default, separators, or a validator)
      72             : //       We would also avoid the alias/help overload.
      73             : //
      74             : struct option
      75             : {
      76             :     short_name_t        f_short_name = NO_SHORT_NAME;   // letter option (or '\0')
      77             :     flag_t              f_flags = GETOPT_FLAG_NONE;     // set of flags
      78             :     char const *        f_name = nullptr;               // name of the option (i.e. "test" for --test, or nullptr)
      79             :     char const *        f_default = nullptr;            // a default value if not nullptr
      80             :     char const *        f_help = nullptr;               // help for this option, if nullptr it's a hidden option; if ALIAS then this is the actual alias
      81             :     char const *        f_validator = nullptr;          // the name of a validator and optional parameters between parenthesis
      82             :     char const * const *f_multiple_separators = nullptr;// nullptr terminated list of strings used as separators when GETOPT_FLAG_MULTIPLE is set
      83             : };
      84             : 
      85             : 
      86             : 
      87             : template<typename T>
      88             : class OptionValue
      89             : {
      90             : public:
      91             :     typedef T   value_t;
      92             : 
      93         247 :     constexpr OptionValue<T>(T const v)
      94         247 :         : f_value(v)
      95             :     {
      96         247 :     }
      97             : 
      98         171 :     constexpr value_t get() const
      99             :     {
     100         171 :         return f_value;
     101             :     }
     102             : 
     103             : private:
     104             :     value_t     f_value;
     105             : };
     106             : 
     107             : 
     108             : class ShortName
     109             :     : public OptionValue<short_name_t>
     110             : {
     111             : public:
     112          19 :     constexpr ShortName()
     113          19 :         : OptionValue<short_name_t>(NO_SHORT_NAME)
     114             :     {
     115          19 :     }
     116             : 
     117          12 :     constexpr ShortName(short_name_t name)
     118          12 :         : OptionValue<short_name_t>(name)
     119             :     {
     120          12 :     }
     121             : };
     122             : 
     123             : class Flags
     124             :     : public OptionValue<flag_t>
     125             : {
     126             : public:
     127          19 :     constexpr Flags()
     128          19 :         : OptionValue<flag_t>(GETOPT_FLAG_NONE)
     129             :     {
     130          19 :     }
     131             : 
     132          19 :     constexpr Flags(flag_t flags)
     133          19 :         : OptionValue<flag_t>(flags)
     134             :     {
     135          19 :     }
     136             : };
     137             : 
     138             : class Name
     139             :     : public OptionValue<char const *>
     140             : {
     141             : public:
     142             :     constexpr Name()
     143             :         : OptionValue<char const *>(nullptr)
     144             :     {
     145             :     }
     146             : 
     147          19 :     constexpr Name(char const * name)
     148          19 :         : OptionValue<char const *>(name)
     149             :     {
     150          19 :     }
     151             : };
     152             : 
     153             : class DefaultValue
     154             :     : public OptionValue<char const *>
     155             : {
     156             : public:
     157          19 :     constexpr DefaultValue()
     158          19 :         : OptionValue<char const *>(nullptr)
     159             :     {
     160          19 :     }
     161             : 
     162          10 :     constexpr DefaultValue(char const * default_value)
     163          10 :         : OptionValue<char const *>(default_value)
     164             :     {
     165          10 :     }
     166             : };
     167             : 
     168             : class Alias
     169             :     : public OptionValue<char const *>
     170             : {
     171             : public:
     172          38 :     constexpr Alias()
     173          38 :         : OptionValue<char const *>(nullptr)
     174             :     {
     175          38 :     }
     176             : 
     177             :     constexpr Alias(char const * alias)
     178             :         : OptionValue<char const *>(alias)
     179             :     {
     180             :     }
     181             : };
     182             : 
     183             : class Help
     184             :     : public OptionValue<char const *>
     185             : {
     186             : public:
     187          19 :     constexpr Help()
     188          19 :         : OptionValue<char const *>(nullptr)
     189             :     {
     190          19 :     }
     191             : 
     192          19 :     constexpr Help(char const * help)
     193          19 :         : OptionValue<char const *>(help)
     194             :     {
     195          19 :     }
     196             : };
     197             : 
     198             : class Validator
     199             :     : public OptionValue<char const *>
     200             : {
     201             : public:
     202          19 :     constexpr Validator()
     203          19 :         : OptionValue<char const *>(nullptr)
     204             :     {
     205          19 :     }
     206             : 
     207             :     constexpr Validator(char const * validator)
     208             :         : OptionValue<char const *>(validator)
     209             :     {
     210             :     }
     211             : };
     212             : 
     213             : class Separators
     214             :     : public OptionValue<char const * const *>
     215             : {
     216             : public:
     217          19 :     constexpr Separators()
     218          19 :         : OptionValue<char const * const *>(nullptr)
     219             :     {
     220          19 :     }
     221             : 
     222          16 :     constexpr Separators(char const * const * separators)
     223          16 :         : OptionValue<char const * const *>(separators)
     224             :     {
     225          16 :     }
     226             : };
     227             : 
     228             : 
     229             : 
     230             : template<typename T, typename F, class ...ARGS>
     231         171 : constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
     232             : {
     233         171 :     snap::NOTUSED(args...);
     234         171 :     return first.get();
     235             : }
     236             : 
     237             : 
     238             : template<typename T, typename F, class ...ARGS>
     239         570 : constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
     240             : {
     241         570 :     snap::NOTUSED(first);
     242         570 :     return find_option<T>(args...);
     243             : }
     244             : 
     245             : 
     246             : 
     247             : template<class ...ARGS>
     248          19 : constexpr option define_option(ARGS ...args)
     249             : {
     250             : #pragma GCC diagnostic push
     251             : #pragma GCC diagnostic ignored "-Wpedantic"
     252         133 :     option opt =
     253             :     {
     254          38 :         .f_short_name =          find_option<ShortName   >(args..., ShortName()),
     255          38 :         .f_flags =               find_option<Flags       >(args..., Flags())
     256          57 :                                     | (find_option<Alias       >(args..., Alias()) != nullptr
     257          19 :                                             ? GETOPT_FLAG_ALIAS
     258             :                                             : GETOPT_FLAG_NONE),
     259          19 :         .f_name =                find_option<Name        >(args...),    // no default, must be defined
     260          38 :         .f_default =             find_option<DefaultValue>(args..., DefaultValue()),
     261          38 :         .f_help =                find_option<Alias       >(args..., Alias()) != nullptr
     262          57 :                                     ? find_option<Alias       >(args..., Alias())
     263          38 :                                     : find_option<Help        >(args..., Help()),
     264          38 :         .f_validator =           find_option<Validator   >(args..., Validator()),
     265          38 :         .f_multiple_separators = find_option<Separators  >(args..., Separators()),
     266             :     };
     267             : #pragma GCC diagnostic pop
     268             : 
     269             :     // TODO: once possible (C++17/20?) add verification tests here
     270             : 
     271          19 :     return opt;
     272             : }
     273             : 
     274             : 
     275             : 
     276             : 
     277             : 
     278             : constexpr option end_options()
     279             : {
     280             :     return define_option(
     281             :               advgetopt::Name(nullptr)
     282             :             , advgetopt::Flags(advgetopt::end_flags())
     283             :         );
     284             : }
     285             : 
     286             : 
     287             : 
     288             : 
     289             : 
     290             : 
     291             : 
     292             : 
     293             : struct group_description
     294             : {
     295             :     flag_t          f_group = GETOPT_FLAG_GROUP_NONE;   // the default is used to mark the end of the list
     296             :     char const *    f_name = nullptr;                   // for --<name>-help
     297             :     char const *    f_description = nullptr;            // for usage() output
     298             : };
     299             : 
     300             : 
     301             : 
     302             : 
     303             : template<typename T>
     304             : class GroupValue
     305             : {
     306             : public:
     307             :     typedef T   value_t;
     308             : 
     309             :     constexpr GroupValue<T>(T const v)
     310             :         : f_value(v)
     311             :     {
     312             :     }
     313             : 
     314             :     constexpr value_t get() const
     315             :     {
     316             :         return f_value;
     317             :     }
     318             : 
     319             : private:
     320             :     value_t     f_value;
     321             : };
     322             : 
     323             : class GroupNumber
     324             :     : public OptionValue<flag_t>
     325             : {
     326             : public:
     327             :     constexpr GroupNumber()
     328             :         : OptionValue<flag_t>(GETOPT_FLAG_GROUP_NONE)
     329             :     {
     330             :     }
     331             : 
     332             :     constexpr GroupNumber(flag_t group)
     333             :         : OptionValue<flag_t>(group)
     334             :     {
     335             :     }
     336             : };
     337             : 
     338             : class GroupName
     339             :     : public GroupValue<char const *>
     340             : {
     341             : public:
     342             :     constexpr GroupName()
     343             :         : GroupValue<char const *>(nullptr)
     344             :     {
     345             :     }
     346             : 
     347             :     constexpr GroupName(char const * name)
     348             :         : GroupValue<char const *>(name)
     349             :     {
     350             :     }
     351             : };
     352             : 
     353             : class GroupDescription
     354             :     : public GroupValue<char const *>
     355             : {
     356             : public:
     357             :     constexpr GroupDescription()
     358             :         : GroupValue<char const *>(nullptr)
     359             :     {
     360             :     }
     361             : 
     362             :     constexpr GroupDescription(char const * description)
     363             :         : GroupValue<char const *>(description)
     364             :     {
     365             :     }
     366             : };
     367             : 
     368             : 
     369             : template<typename T, typename F, class ...ARGS>
     370             : constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_group(F first, ARGS ...args)
     371             : {
     372             :     snap::NOTUSED(args...);
     373             :     return first.get();
     374             : }
     375             : 
     376             : 
     377             : template<typename T, typename F, class ...ARGS>
     378             : constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_group(F first, ARGS ...args)
     379             : {
     380             :     snap::NOTUSED(first);
     381             :     return find_group<T>(args...);
     382             : }
     383             : 
     384             : 
     385             : 
     386             : template<class ...ARGS>
     387             : constexpr group_description define_group(ARGS ...args)
     388             : {
     389             : #pragma GCC diagnostic push
     390             : #pragma GCC diagnostic ignored "-Wpedantic"
     391             :     group_description grp =
     392             :     {
     393             :         .f_group =              find_group<GroupNumber     >(args..., GroupNumber()),
     394             :         .f_name =               find_group<GroupName       >(args..., GroupName()),
     395             :         .f_description =        find_group<GroupDescription>(args..., GroupDescription()),
     396             :     };
     397             : #pragma GCC diagnostic pop
     398             : 
     399             :     return grp;
     400             : }
     401             : 
     402             : 
     403             : constexpr group_description end_groups()
     404             : {
     405             :     // the defaults are what we expect to end the list of groups
     406             :     return define_group();
     407             : }
     408             : 
     409             : 
     410             : 
     411             : 
     412             : 
     413             : 
     414             : 
     415             : 
     416             : constexpr flag_t    GETOPT_ENVIRONMENT_FLAG_DYNAMIC_PARAMETERS          = 0x0001;   // accept parameters that are not declared
     417             : 
     418             : constexpr flag_t    GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS           = 0x0002;   // add system parameters (i.e. --help, --version, etc.)
     419             : constexpr flag_t    GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS   = 0x0004;   // add & process system parameters
     420             : 
     421             : 
     422         333 : struct options_environment
     423             : {
     424             :     char const *                f_project_name = nullptr;               // project/application name--used as filename for the .conf files (%a)
     425             :     char const *                f_group_name = nullptr;                 // sub-folder name (i.e. "snapwebsites")--if nullptr, use f_project_name
     426             :     option const *              f_options = nullptr;                    // raw options
     427             :     char const *                f_options_files_directory = nullptr;    // directory to check for option files (default "/usr/shared/advgetopt")
     428             :     char const *                f_environment_variable_name = nullptr;  // environment variable with additional options (%e)
     429             :     char const * const *        f_configuration_files = nullptr;        // nullptr terminated array of full paths to configuration files (%f)
     430             :     char const *                f_configuration_filename = nullptr;     // the configuration filename to search in f_configuration_directories (%g)
     431             :     char const * const *        f_configuration_directories = nullptr;  // nullptr terminated array of paths only to configuration files (%d)
     432             :     flag_t                      f_environment_flags = 0;                // GETOPT_ENVIRONMENT_FLAG_...
     433             :     char const *                f_help_header = nullptr;                // show on --help
     434             :     char const *                f_help_footer = nullptr;                // show on --help
     435             :     char const *                f_version = nullptr;                    // show on --version and %v
     436             :     char const *                f_license = nullptr;                    // show on --license and %l
     437             :     char const *                f_copyright = nullptr;                  // show on --copyright and %c
     438             :     char const *                f_build_date = UTC_BUILD_DATE;          // available to parameter %b
     439             :     char const *                f_build_time = UTC_BUILD_TIME;          // available to parameter %t
     440             :     group_description const *   f_groups = nullptr;                     // nullptr terminated array of group names
     441             : };
     442             : 
     443             : 
     444             : 
     445             : 
     446             : 
     447             : }   // namespace advgetopt
     448             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13