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

Generated by: LCOV version 1.12