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-07-15 03:11:49 Functions: 117 117 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12