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: 2021-08-20 21:57:12 Functions: 117 117 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13