LCOV - code coverage report
Current view: top level - advgetopt - options.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 71 71 100.0 %
Date: 2022-05-26 21:41:34 Functions: 133 133 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13