LCOV - code coverage report
Current view: top level - advgetopt - options.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 70 70
Test Date: 2026-01-18 09:38:57 Functions: 100.0 % 132 132
Legend: Lines: hit not hit

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

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions