LCOV - code coverage report
Current view: top level - advgetopt - advgetopt_options.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 192 210 91.4 %
Date: 2022-05-26 21:41:34 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2006-2022  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/advgetopt
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : 
      20             : /** \file
      21             :  * \brief Advanced getopt data access implementation.
      22             :  *
      23             :  * The advgetopt class has many function used to access the data in the
      24             :  * class. These functions are gathered here.
      25             :  *
      26             :  * This file is covered by the following tests:
      27             :  *
      28             :  * \li options_parser
      29             :  * \li invalid_options_parser
      30             :  * \li valid_options_files
      31             :  * \li invalid_options_files
      32             :  */
      33             : 
      34             : // self
      35             : //
      36             : #include    "advgetopt/advgetopt.h"
      37             : 
      38             : 
      39             : // advgetopt lib
      40             : //
      41             : #include    "advgetopt/conf_file.h"
      42             : #include    "advgetopt/exception.h"
      43             : 
      44             : 
      45             : // cppthread lib
      46             : //
      47             : #include    <cppthread/log.h>
      48             : 
      49             : 
      50             : // snapdev lib
      51             : //
      52             : #include    <snapdev/tokenize_string.h>
      53             : 
      54             : 
      55             : // C++ lib
      56             : //
      57             : #include    <list>
      58             : 
      59             : 
      60             : // last include
      61             : //
      62             : #include    <snapdev/poison.h>
      63             : 
      64             : 
      65             : 
      66             : 
      67             : namespace advgetopt
      68             : {
      69             : 
      70             : 
      71             : 
      72             : 
      73             : 
      74             : 
      75             : 
      76             : /** \brief Reset all the options.
      77             :  *
      78             :  * This function goes through the list of options and mark them all as
      79             :  * undefined. This is useful if you want to reuse a getopt object.
      80             :  *
      81             :  * The effect is that all calls to is_defined() made afterward return false
      82             :  * until new arguments get parsed.
      83             :  */
      84           2 : void getopt::reset()
      85             : {
      86          18 :     for(auto & opt : f_options_by_name)
      87             :     {
      88          16 :         opt.second->reset();
      89             :     }
      90           2 : }
      91             : 
      92             : 
      93             : /** \brief Parse the options to option_info objects.
      94             :  *
      95             :  * This function transforms an array of options in a vector of option_info
      96             :  * objects.
      97             :  *
      98             :  * \param[in] opts  An array of options to be parsed.
      99             :  * \param[in] ignore_duplicates  Whether to ignore potential duplicates.
     100             :  */
     101         465 : void getopt::parse_options_info(option const * opts, bool ignore_duplicates)
     102             : {
     103         465 :     if(opts == nullptr)
     104             :     {
     105          64 :         return;
     106             :     }
     107             : 
     108        1591 :     for(
     109        1992 :       ; (opts->f_flags & GETOPT_FLAG_END) == 0
     110             :       ; ++opts)
     111             :     {
     112        1599 :         if(opts->f_name == nullptr
     113        1598 :         || opts->f_name[0] == '\0')
     114             :         {
     115           2 :             throw getopt_logic_error("option long name missing or empty.");
     116             :         }
     117        1597 :         short_name_t const one_char(string_to_short_name(opts->f_name));
     118        1597 :         if(one_char != NO_SHORT_NAME)
     119             :         {
     120           1 :             throw getopt_logic_error("a long name option must be at least 2 characters.");
     121             :         }
     122             : 
     123        1596 :         short_name_t short_name(opts->f_short_name);
     124             : 
     125        1596 :         option_info::pointer_t o(std::make_shared<option_info>(
     126             :                                               opts->f_name
     127        3191 :                                             , short_name));
     128        1595 :         o->set_variables(f_variables);
     129             : 
     130        1595 :         o->set_environment_variable_name(opts->f_environment_variable_name);
     131        1595 :         o->add_flag(opts->f_flags);
     132        1595 :         o->set_default(opts->f_default);
     133        1595 :         o->set_help(opts->f_help);
     134        1595 :         o->set_multiple_separators(opts->f_multiple_separators);
     135             : 
     136        1595 :         if(opts->f_validator != nullptr)
     137             :         {
     138           6 :             o->set_validator(opts->f_validator);
     139             :         }
     140             : 
     141        1599 :         add_option(o, ignore_duplicates);
     142             :     }
     143             : }
     144             : 
     145             : 
     146             : /** \brief Add one option to the advgetopt object.
     147             :  *
     148             :  * This function is used to dynamically add one option to the advgetopt
     149             :  * object.
     150             :  *
     151             :  * This is often used in a library which wants to dynamically add support
     152             :  * for library specific parameters to the command line.
     153             :  *
     154             :  * \note
     155             :  * The \p ignore_duplicates option still gets the option added if only
     156             :  * the short-name is a duplicate. In that case, we set the option's
     157             :  * short-name to NO_SHORT_NAME before adding the option to the tables.
     158             :  *
     159             :  * \param[in] opt  The option to be added.
     160             :  * \param[in] ignore_duplicate  If option is a duplicate, do not add it.
     161             :  */
     162        1608 : void getopt::add_option(option_info::pointer_t opt, bool ignore_duplicates)
     163             : {
     164        1608 :     if(get_option(opt->get_name(), true) != nullptr)
     165             :     {
     166           2 :         if(ignore_duplicates)
     167             :         {
     168           1 :             return;
     169             :         }
     170             :         throw getopt_logic_error(
     171           2 :                   std::string("option named \"")
     172           3 :                 + opt->get_name()
     173           3 :                 + "\" found twice.");
     174             :     }
     175             : 
     176        1606 :     short_name_t short_name(opt->get_short_name());
     177        1606 :     if(get_option(short_name, true) != nullptr)
     178             :     {
     179           2 :         if(ignore_duplicates)
     180             :         {
     181           1 :             short_name = NO_SHORT_NAME;
     182           1 :             opt->set_short_name(NO_SHORT_NAME);
     183             :         }
     184             :         else
     185             :         {
     186             :             throw getopt_logic_error(
     187             :                       "option with short name \""
     188           2 :                     + short_name_to_string(short_name)
     189           3 :                     + "\" found twice.");
     190             :         }
     191             :     }
     192             : 
     193        1605 :     if(opt->is_default_option())
     194             :     {
     195          48 :         if(f_default_option != nullptr)
     196             :         {
     197           1 :             throw getopt_logic_error("two default options found.");
     198             :         }
     199          47 :         if(opt->has_flag(GETOPT_FLAG_FLAG))
     200             :         {
     201           1 :             throw getopt_logic_error("a default option must accept parameters, it can't be a GETOPT_FLAG_FLAG.");
     202             :         }
     203             : 
     204          46 :         f_default_option = opt;
     205             :     }
     206             : 
     207        1603 :     f_options_by_name[opt->get_name()] = opt;
     208             : 
     209        1603 :     if(short_name != NO_SHORT_NAME)
     210             :     {
     211         696 :         f_options_by_short_name[short_name] = opt;
     212             :     }
     213             : }
     214             : 
     215             : 
     216             : /** \brief Check for a file with option definitions.
     217             :  *
     218             :  * This function tries to read the default option file for this process.
     219             :  * This filename is generated using the the option environment files
     220             :  * directory and the project name.
     221             :  *
     222             :  * If the directory is not defined, the function uses this default path:
     223             :  * `"/usr/share/advgetopt/options/"`. See the other
     224             :  * parse_options_from_file(std::string const & filename, int min_sections, int max_sections)
     225             :  * function for additional details.
     226             :  *
     227             :  * \sa parse_options_from_file(std::string const & filename, int min_sections, int max_sections)
     228             :  */
     229         343 : void getopt::parse_options_from_file()
     230             : {
     231         677 :     std::string filename;
     232             : 
     233         343 :     if(f_options_environment.f_project_name == nullptr
     234         339 :     || f_options_environment.f_project_name[0] == '\0')
     235             :     {
     236           6 :         return;
     237             :     }
     238             : 
     239         337 :     if(f_options_environment.f_options_files_directory == nullptr
     240          73 :     || f_options_environment.f_options_files_directory[0] == '\0')
     241             :     {
     242         266 :         filename = "/usr/share/advgetopt/options/";
     243             :     }
     244             :     else
     245             :     {
     246          71 :         filename = f_options_environment.f_options_files_directory;
     247          71 :         if(filename.back() != '/')
     248             :         {
     249          71 :             filename += '/';
     250             :         }
     251             :     }
     252         337 :     filename += f_options_environment.f_project_name;
     253         337 :     filename += ".ini";
     254             : 
     255         337 :     parse_options_from_file(filename, 1, 1);
     256             : }
     257             : 
     258             : 
     259             : /** \brief Check for a file with option definitions.
     260             :  *
     261             :  * This function tries to read the specified file for command line options
     262             :  * for this application. These are similar to the option structure, only it
     263             :  * is defined in a file.
     264             :  *
     265             :  * The format of the file is like so:
     266             :  *
     267             :  * \li Option names are defined on a line by themselves between square brackets.
     268             :  * \li Parameters of that option are defined below as a `name=<value>`.
     269             :  *
     270             :  * Example:
     271             :  *
     272             :  * \code
     273             :  *     [<command-name>]
     274             :  *     short_name=<character>
     275             :  *     default=<default value>
     276             :  *     help=<help sentence>
     277             :  *     validator=<validator name>[(<param>)]|/<regex>/<flags>
     278             :  *     alias=<name of aliased option>
     279             :  *     allowed=command-line,environment-variable,configuration-file
     280             :  *     show-usage-on-error
     281             :  *     no-arguments|multiple
     282             :  *     required
     283             :  * \endcode
     284             :  *
     285             :  * The number of namespaces in `<command-name>` can be limited using the
     286             :  * \p min_sections and \p max_sections parameters.
     287             :  *
     288             :  * The function can be called multiple times. The first time, it verifies
     289             :  * that there are not duplicated settings. On following loads, that test
     290             :  * is ignored.
     291             :  *
     292             :  * \todo
     293             :  * Test that options get 100% updated on a reload.
     294             :  *
     295             :  * \note
     296             :  * By default, this function is called with one specific filename based
     297             :  * on the f_project_name field and the f_options_files_directory as
     298             :  * defined in the options environment.
     299             :  *
     300             :  * \param[in] filename  The filename to load.
     301             :  * \param[in] min_sections  The minimum number of namespaces.
     302             :  * \param[in] max_sections  The maximum number of namespaces.
     303             :  * \param[in] ignore_duplicates  Whether duplicates are okay or not.
     304             :  *
     305             :  * \sa parse_options_from_file()
     306             :  */
     307         337 : void getopt::parse_options_from_file(
     308             :           std::string const & filename
     309             :         , int min_sections
     310             :         , int max_sections
     311             :         , bool ignore_duplicates)
     312             : {
     313         337 :     section_operator_t operators(SECTION_OPERATOR_INI_FILE);
     314         337 :     if(min_sections == 1
     315         337 :     && max_sections == 1)
     316             :     {
     317         337 :         operators |= SECTION_OPERATOR_ONE_SECTION;
     318             :     }
     319         337 :     conf_file_setup conf_setup(filename
     320             :                              , line_continuation_t::line_continuation_unix
     321             :                              , ASSIGNMENT_OPERATOR_EQUAL
     322             :                              , COMMENT_INI | COMMENT_SHELL
     323         674 :                              , operators);
     324         337 :     if(!conf_setup.is_valid())
     325             :     {
     326             :         return;  // LCOV_EXCL_LINE
     327             :     }
     328             : 
     329         674 :     conf_file::pointer_t conf(conf_file::get_conf_file(conf_setup));
     330         674 :     conf_file::sections_t const & sections(conf->get_sections());
     331         350 :     for(auto & section_names : sections)
     332             :     {
     333          32 :         std::list<std::string> names;
     334          16 :         snapdev::tokenize_string(
     335             :               names
     336             :             , section_names
     337             :             , "::");
     338          32 :         if(names.size() < static_cast<std::size_t>(min_sections)
     339          16 :         || names.size() > static_cast<std::size_t>(max_sections))
     340             :         {
     341           0 :             if(min_sections == 1
     342           0 :             && max_sections == 1)
     343             :             {
     344           0 :                 cppthread::log << cppthread::log_level_t::error
     345           0 :                     << "the name of a settings definition must include one namespace; \""
     346           0 :                     << section_names
     347           0 :                     << "\" is not considered valid."
     348           0 :                     << cppthread::end;
     349             :             }
     350             :             else
     351             :             {
     352           0 :                 cppthread::log << cppthread::log_level_t::error
     353           0 :                     << "the name of a settings definition must include between "
     354           0 :                     << min_sections
     355           0 :                     << " and "
     356           0 :                     << max_sections
     357           0 :                     << " namespaces; \""
     358           0 :                     << section_names
     359           0 :                     << "\" is not considered valid."
     360           0 :                     << cppthread::end;
     361             :             }
     362           0 :             continue;
     363             :         }
     364             : 
     365          32 :         std::string const parameter_name(section_names);
     366          32 :         std::string const short_name(unquote(conf->get_parameter(parameter_name + "::shortname")));
     367          16 :         if(short_name.length() > 1)
     368             :         {
     369             :             throw getopt_logic_error(
     370             :                       "option \""
     371           2 :                     + section_names
     372           3 :                     + "\" has an invalid short name in \""
     373           3 :                     + filename
     374           3 :                     + "\", it can't be more than one character.");
     375             :         }
     376          15 :         short_name_t const sn(short_name.length() == 1
     377          15 :                                     ? short_name[0]
     378          15 :                                     : NO_SHORT_NAME);
     379             : 
     380          30 :         option_info::pointer_t opt(std::make_shared<option_info>(parameter_name, sn));
     381          15 :         opt->set_variables(f_variables);
     382             : 
     383          30 :         std::string const environment_variable_name(parameter_name + "::environment_variable_name");
     384          15 :         if(conf->has_parameter(environment_variable_name))
     385             :         {
     386           0 :             opt->set_environment_variable_name(unquote(conf->get_parameter(environment_variable_name)));
     387             :         }
     388             : 
     389          30 :         std::string const default_name(parameter_name + "::default");
     390          15 :         if(conf->has_parameter(default_name))
     391             :         {
     392           9 :             opt->set_default(unquote(conf->get_parameter(default_name)));
     393             :         }
     394             : 
     395          15 :         opt->set_help(unquote(conf->get_parameter(parameter_name + "::help")));
     396             : 
     397          30 :         std::string const validator_name_and_params(conf->get_parameter(parameter_name + "::validator"));
     398          15 :         opt->set_validator(validator_name_and_params);
     399             : 
     400          28 :         std::string const alias_name(parameter_name + "::alias");
     401          14 :         if(conf->has_parameter(alias_name))
     402             :         {
     403           6 :             if(!opt->get_help().empty())
     404             :             {
     405             :                 throw getopt_logic_error(
     406             :                           "option \""
     407           2 :                         + section_names
     408           3 :                         + "\" is an alias and as such it can't include a help=... parameter in \""
     409           3 :                         + filename
     410           3 :                         + "\".");
     411             :             }
     412           5 :             opt->set_help(unquote(conf->get_parameter(alias_name)));
     413           5 :             opt->add_flag(GETOPT_FLAG_ALIAS);
     414             :         }
     415             : 
     416          26 :         std::string const allowed_name(parameter_name + "::allowed");
     417          13 :         if(conf->has_parameter(allowed_name))
     418             :         {
     419          26 :             std::string const allowed_list(conf->get_parameter(allowed_name));
     420          26 :             string_list_t allowed;
     421          13 :             split_string(allowed_list, allowed, {","});
     422          32 :             for(auto const & a : allowed)
     423             :             {
     424          19 :                 if(a == "command-line")
     425             :                 {
     426          10 :                     opt->add_flag(GETOPT_FLAG_COMMAND_LINE);
     427             :                 }
     428           9 :                 else if(a == "environment-variable")
     429             :                 {
     430           6 :                     opt->add_flag(GETOPT_FLAG_ENVIRONMENT_VARIABLE);
     431             :                 }
     432           3 :                 else if(a == "configuration-file")
     433             :                 {
     434           3 :                     opt->add_flag(GETOPT_FLAG_CONFIGURATION_FILE);
     435             :                 }
     436             :             }
     437             :         }
     438             : 
     439          13 :         if(conf->has_parameter(parameter_name + "::show-usage-on-error"))
     440             :         {
     441           1 :             opt->add_flag(GETOPT_FLAG_SHOW_USAGE_ON_ERROR);
     442             :         }
     443             : 
     444          13 :         if(conf->has_parameter(parameter_name + "::no-arguments"))
     445             :         {
     446           4 :             opt->add_flag(GETOPT_FLAG_FLAG);
     447             :         }
     448             : 
     449          13 :         if(conf->has_parameter(parameter_name + "::multiple"))
     450             :         {
     451           1 :             opt->add_flag(GETOPT_FLAG_MULTIPLE);
     452             :         }
     453             : 
     454          13 :         if(conf->has_parameter(parameter_name + "::required"))
     455             :         {
     456           5 :             opt->add_flag(GETOPT_FLAG_REQUIRED);
     457             :         }
     458             : 
     459          13 :         add_option(opt, ignore_duplicates);
     460             :     }
     461             : }
     462             : 
     463             : 
     464             : /** \brief Link options marked as a GETOPT_FLAG_ALIAS.
     465             :  *
     466             :  * After we defined all the options, go through the list again to find
     467             :  * aliases and link them with their corresponding alias option.
     468             :  *
     469             :  * \exception getopt_exception_invalid
     470             :  * All aliases must exist or this exception is raised.
     471             :  */
     472         262 : void getopt::link_aliases()
     473             : {
     474        1411 :     for(auto & c : f_options_by_name)
     475             :     {
     476        1153 :         if(c.second->has_flag(GETOPT_FLAG_ALIAS))
     477             :         {
     478          22 :             std::string const & alias_name(c.second->get_help());
     479          22 :             if(alias_name.empty())
     480             :             {
     481             :                 throw getopt_logic_error(
     482             :                           "the default value of your alias cannot be an empty string for \""
     483           4 :                         + c.first
     484           6 :                         + "\".");
     485             :             }
     486             : 
     487             :             // we have to use the `true` flag in this get_option() because
     488             :             // aliases may not yet be defined
     489             :             //
     490          40 :             option_info::pointer_t alias(get_option(alias_name, true));
     491          20 :             if(alias == nullptr)
     492             :             {
     493             :                 throw getopt_logic_error(
     494             :                           "no option named \""
     495           2 :                         + alias_name
     496           3 :                         + "\" to satisfy the alias of \""
     497           3 :                         + c.first
     498           3 :                         + "\".");
     499             :             }
     500             : 
     501          19 :             flag_t const expected_flags(c.second->get_flags() & ~GETOPT_FLAG_ALIAS);
     502          19 :             if(alias->get_flags() != expected_flags)
     503             :             {
     504           2 :                 std::stringstream ss;
     505           1 :                 ss << std::hex
     506             :                    << "the flags of alias \""
     507             :                    << c.first
     508           1 :                    << "\" (0x"
     509           1 :                    << expected_flags
     510             :                    << ") are different than the flags of \""
     511             :                    << alias_name
     512           1 :                    << "\" (0x"
     513           1 :                    << alias->get_flags()
     514           1 :                    << ").";
     515           1 :                 throw getopt_logic_error(ss.str());
     516             :             }
     517             : 
     518          18 :             c.second->set_alias_destination(alias);
     519             :         }
     520             :     }
     521         258 : }
     522             : 
     523             : 
     524             : /** \brief Assign a short name to an option.
     525             :  *
     526             :  * This function allows for dynamically assigning a short name to an option.
     527             :  * This is useful for cases where a certain number of options may be added
     528             :  * dynamically and may share the same short name or similar situation.
     529             :  *
     530             :  * On our end we like to add `-c` as the short name of the `--config-dir`
     531             :  * command line or environment variable option. However, some of our tools
     532             :  * use `-c` for other reason (i.e. our `cxpath` tool uses `-c` for its
     533             :  * `--compile` option.) So we do not want to have it as a default in
     534             :  * `--config-dir`. Instead we assign it afterward if possible.
     535             :  *
     536             :  * **IMPORTANT:** It is possible to change the short-name at any time.
     537             :  * However, note that you can't have duplicates. It is also possible
     538             :  * to remove a short-name by setting it to the advgetopt::NO_SHORT_NAME
     539             :  * special value.
     540             :  *
     541             :  * \note
     542             :  * This function requires you to make use of the constructor without the
     543             :  * `argc` and `argv` parameters, add the short name, then run all the
     544             :  * parsing.
     545             :  *
     546             :  * \exception getopt_exception_logic
     547             :  * The same short name cannot be used more than once. This exception is
     548             :  * raised if it is discovered that another option already makes use of
     549             :  * this short name. This exception is also raised if \p name does not
     550             :  * reference an existing option.
     551             :  *
     552             :  * \param[in] name  The name of the option which is to receive a short name.
     553             :  * \param[in] short_name  The short name to assigned to the \p name option.
     554             :  */
     555           9 : void getopt::set_short_name(std::string const & name, short_name_t short_name)
     556             : {
     557           9 :     auto opt(f_options_by_name.find(name));
     558           9 :     if(opt == f_options_by_name.end())
     559             :     {
     560             :         throw getopt_logic_error(
     561             :                   "option with name \""
     562           2 :                 + name
     563           3 :                 + "\" not found.");
     564             :     }
     565             : 
     566           8 :     if(short_name != NO_SHORT_NAME)
     567             :     {
     568           6 :         auto it(f_options_by_short_name.find(short_name));
     569           6 :         if(it != f_options_by_short_name.end())
     570             :         {
     571           2 :             if(it->second == opt->second)
     572             :             {
     573             :                 // same option, already named 'short_name'
     574             :                 //
     575           1 :                 return;
     576             :             }
     577             : 
     578             :             throw getopt_logic_error(
     579             :                       "found another option (\""
     580           2 :                     + it->second->get_name()
     581           3 :                     + "\") with short name '"
     582           4 :                     + short_name_to_string(short_name)
     583           3 :                     + "'.");
     584             :         }
     585             :     }
     586             : 
     587           6 :     short_name_t const old_short_name(opt->second->get_short_name());
     588           6 :     if(old_short_name != NO_SHORT_NAME)
     589             :     {
     590           2 :         auto it(f_options_by_short_name.find(old_short_name));
     591           2 :         if(it != f_options_by_short_name.end())
     592             :         {
     593           2 :             f_options_by_short_name.erase(it);
     594             :         }
     595             :     }
     596             : 
     597           6 :     opt->second->set_short_name(short_name);
     598             : 
     599           6 :     if(short_name != NO_SHORT_NAME)
     600             :     {
     601           4 :         f_options_by_short_name[short_name] = opt->second;
     602             :     }
     603             : }
     604             : 
     605             : 
     606             : /** \brief Output the source of each option.
     607             :  *
     608             :  * This function goes through the list of options by name ("alphabetically")
     609             :  * and prints out the sources or "(undefined)" if not defined anywhere.
     610             :  *
     611             :  * This function gets called when using the `--show-option-sources`
     612             :  * system command line option at the time the process_system_options()
     613             :  * function gets called.
     614             :  *
     615             :  * \param[in] out  The output streaming where the info is written.
     616             :  */
     617           3 : void getopt::show_option_sources(std::basic_ostream<char> & out)
     618             : {
     619           3 :     int idx(1);
     620           3 :     out << "Option Sources:\n";
     621          64 :     for(auto const & opt : f_options_by_name)
     622             :     {
     623          61 :         out << "  " << idx << ". option \"" << opt.second->get_name() << "\"";
     624         122 :         string_list_t sources(opt.second->trace_sources());
     625          61 :         if(sources.empty())
     626             :         {
     627          29 :             out << " (undefined)\n";
     628             :         }
     629             :         else
     630             :         {
     631          32 :             out << "\n";
     632          84 :             for(auto const & src : sources)
     633             :             {
     634          52 :                 out << "     " << src << "\n";
     635             :             }
     636             :         }
     637          61 :         out << "\n";
     638             : 
     639          61 :         ++idx;
     640             :     }
     641           3 :     out << std::flush;
     642           3 : }
     643             : 
     644             : 
     645             : 
     646           6 : } // namespace advgetopt
     647             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13