LCOV - code coverage report
Current view: top level - src - ProgOptions.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 266 486 54.7 %
Date: 2020-12-16 07:07:30 Functions: 43 59 72.9 %
Branches: 451 2095 21.5 %

           Branch data     Line data    Source code
       1                 :            : #include <iostream>
       2                 :            : #include <sstream>
       3                 :            : #include <iomanip>
       4                 :            : #include <cstdlib>
       5                 :            : #include <list>
       6                 :            : #include <limits>
       7                 :            : #include <set>
       8                 :            : #include <algorithm>
       9                 :            : 
      10                 :            : #include <assert.h>
      11                 :            : #include <string.h>
      12                 :            : 
      13                 :            : #include "moab/MOABConfig.h"
      14                 :            : #include "moab/ProgOptions.hpp"
      15                 :            : #ifdef MOAB_HAVE_MPI
      16                 :            : #include "moab_mpi.h"
      17                 :            : #endif
      18                 :            : 
      19                 :            : enum OptType
      20                 :            : {
      21                 :            :     FLAG = 0,
      22                 :            :     INT,
      23                 :            :     REAL,
      24                 :            :     STRING,
      25                 :            :     INT_VECT
      26                 :            : };
      27                 :            : 
      28                 :            : template < typename T >
      29                 :            : inline static OptType get_opt_type();
      30                 :            : 
      31                 :            : template <>
      32                 :         40 : OptType get_opt_type< void >()
      33                 :            : {
      34                 :         40 :     return FLAG;
      35                 :            : }
      36                 :            : template <>
      37                 :         25 : OptType get_opt_type< int >()
      38                 :            : {
      39                 :         25 :     return INT;
      40                 :            : }
      41                 :            : template <>
      42                 :         15 : OptType get_opt_type< double >()
      43                 :            : {
      44                 :         15 :     return REAL;
      45                 :            : }
      46                 :            : template <>
      47                 :         42 : OptType get_opt_type< std::string >()
      48                 :            : {
      49                 :         42 :     return STRING;
      50                 :            : }
      51                 :            : template <>
      52                 :          5 : OptType get_opt_type< std::vector< int > >()
      53                 :            : {
      54                 :          5 :     return INT_VECT;
      55                 :            : }
      56                 :            : 
      57                 :        196 : class ProgOpt
      58                 :            : {
      59                 :            : 
      60                 :            :     std::string shortname, longname;
      61                 :            :     std::vector< std::string > args;
      62                 :            :     OptType type;
      63                 :            :     void* storage;
      64                 :            :     int flags;
      65                 :            :     ProgOpt* cancel_opt;
      66                 :            : 
      67                 :          0 :     const char* get_argstring() const
      68                 :            :     {
      69   [ #  #  #  #  :          0 :         switch( type )
                      # ]
      70                 :            :         {
      71                 :            :             case INT:
      72                 :          0 :                 return "int";
      73                 :            :             case INT_VECT:
      74                 :          0 :                 return "ints";
      75                 :            :             case REAL:
      76                 :          0 :                 return "val";
      77                 :            :             case FLAG:
      78                 :          0 :                 return "";
      79                 :            :             default:
      80                 :          0 :                 return "arg";
      81                 :            :         }
      82                 :            :     }
      83                 :            : 
      84                 :            :   public:
      85                 :         98 :     ProgOpt( const std::string& longname_p, const std::string& shortname_p, int flags_p, OptType t = FLAG )
      86                 :            :         : shortname( shortname_p ), longname( longname_p ), type( t ), storage( NULL ), flags( flags_p ),
      87 [ +  - ][ +  - ]:         98 :           cancel_opt( NULL )
      88                 :            :     {
      89                 :         98 :     }
      90                 :            : 
      91                 :            :     friend class ProgOptions;
      92                 :            : };
      93                 :            : 
      94                 :         25 : ProgOptions::ProgOptions( const std::string& helpstring, const std::string& briefhelp )
      95 [ +  - ][ +  - ]:         25 :     : expect_optional_args( false ), optional_args_position( 0 ), max_optional_args( 0 )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
      96                 :            : {
      97         [ +  - ]:         25 :     brief_help = briefhelp;
      98 [ +  + ][ +  - ]:         25 :     if( !helpstring.empty() ) main_help.push_back( helpstring );
      99 [ +  - ][ +  - ]:         25 :     addOpt< void >( "help,h", "Show full help text", help_flag );
                 [ +  - ]
     100                 :         25 : }
     101                 :            : 
     102                 :         50 : ProgOptions::~ProgOptions()
     103                 :            : {
     104         [ +  + ]:        104 :     for( std::vector< help_line >::iterator i = option_help_strings.begin(); i != option_help_strings.end(); ++i )
     105                 :            :     {
     106 [ +  - ][ +  - ]:         79 :         if( ( *i ).first ) { delete( *i ).first; }
     107                 :            :     }
     108                 :            : 
     109         [ +  + ]:         44 :     for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
     110                 :            :     {
     111         [ +  - ]:         19 :         delete( *i ).first;
     112                 :            :     }
     113                 :         25 : }
     114                 :            : 
     115                 :        109 : void ProgOptions::get_namestrings( const std::string& namestring, std::string* longname, std::string* shortname )
     116                 :            : {
     117                 :        109 :     *shortname = "";
     118                 :        109 :     *longname  = namestring;
     119                 :            : 
     120                 :        109 :     size_t idx = namestring.find_first_of( ',' );
     121         [ +  + ]:        109 :     if( idx != namestring.npos )
     122                 :            :     {
     123         [ +  - ]:         96 :         *longname  = namestring.substr( 0, idx );
     124         [ +  - ]:         96 :         *shortname = namestring.substr( idx + 1, namestring.npos );
     125                 :            :     }
     126                 :        109 : }
     127                 :            : 
     128                 :          0 : void ProgOptions::setVersion( const std::string& version_string, bool addFlag )
     129                 :            : {
     130                 :          0 :     progversion = version_string;
     131 [ #  # ][ #  # ]:          0 :     if( addFlag ) { addOpt< void >( "version", "Print version number and exit", version_flag ); }
         [ #  # ][ #  # ]
     132                 :          0 : }
     133                 :            : 
     134                 :            : template < typename T >
     135                 :         76 : void ProgOptions::addOpt( const std::string& namestring, const std::string& helpstring, T* value, int flags )
     136                 :            : {
     137                 :            : 
     138 [ +  - ][ +  - ]:        152 :     std::string shortname, longname;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     139 [ +  - ][ +  - ]:         76 :     get_namestrings( namestring, &longname, &shortname );
         [ +  - ][ +  - ]
                 [ +  - ]
     140                 :            : 
     141 [ -  + ][ -  + ]:         76 :     if( flags & int_flag )
         [ -  + ][ -  + ]
                 [ -  + ]
     142                 :            :     {  // short name is implicit for this flag
     143 [ #  # ][ #  # ]:          0 :         if( !shortname.empty() ) error( "Requested short name with int_flag option" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     144 [ #  # ][ #  # ]:          0 :         if( get_opt_type< T >() != INT ) error( "Requested int_flag for non-integer option" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     145 [ #  # ][ #  # ]:          0 :         if( !number_option_name.empty() ) error( "Requested int_flag for multiple options" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     146 [ #  # ][ #  # ]:          0 :         number_option_name = longname;
         [ #  # ][ #  # ]
                 [ #  # ]
     147                 :            :     }
     148                 :            : 
     149 [ +  - ][ +  - ]:         76 :     ProgOpt* opt = new ProgOpt( longname, shortname, flags, get_opt_type< T >() );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     150 [ +  - ][ +  + ]:         76 :     if( value ) opt->storage = value;
         [ +  - ][ +  - ]
                 [ +  + ]
     151                 :            : 
     152 [ +  - ][ +  - ]:         76 :     if( longname.length() ) long_names[longname] = opt;
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
     153 [ +  - ][ +  - ]:         76 :     if( shortname.length() ) short_names[shortname] = opt;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
     154                 :            : 
     155 [ +  - ][ +  - ]:        152 :     help_line help = std::make_pair( opt, helpstring );
         [ +  - ][ +  - ]
                 [ +  - ]
     156 [ +  - ][ +  - ]:         76 :     option_help_strings.push_back( help );
         [ +  - ][ +  - ]
                 [ +  - ]
     157                 :            : 
     158 [ -  + ][ -  + ]:         76 :     if( flags & add_cancel_opt )
         [ -  + ][ -  + ]
                 [ +  + ]
     159                 :            :     {
     160 [ #  # ][ #  # ]:          3 :         std::string flag    = "no-" + ( longname.length() ? longname : shortname );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
     161 [ #  # ][ #  # ]:          3 :         ProgOpt* cancel_opt = new ProgOpt( flag, "", flags ^ ProgOptions::store_false, FLAG );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
                 [ +  - ]
     162 [ #  # ][ #  # ]:          3 :         if( value ) cancel_opt->storage = value;
         [ #  # ][ #  # ]
                 [ +  - ]
     163                 :            : 
     164                 :          3 :         cancel_opt->cancel_opt       = opt;
     165 [ #  # ][ #  # ]:          3 :         long_names[flag]             = cancel_opt;
         [ #  # ][ #  # ]
                 [ +  - ]
     166 [ #  # ][ #  # ]:          6 :         std::string clear_helpstring = "Clear previous " + flag.substr( 3, flag.npos ) + " flag";
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
                 [ +  - ]
     167 [ #  # ][ #  # ]:          3 :         help                         = std::make_pair( cancel_opt, clear_helpstring );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
     168   [ #  #  #  #  :          6 :         option_help_strings.push_back( help );
          #  #  #  #  +  
                      - ]
     169                 :         76 :     }
     170                 :         76 : }
     171                 :            : 
     172                 :            : template < typename T >
     173                 :         19 : void ProgOptions::addRequiredArg( const std::string& helpname, const std::string& helpstring, T* value, int flags )
     174                 :            : {
     175                 :            : 
     176                 :         19 :     OptType type = get_opt_type< T >();
     177                 :            : 
     178 [ +  - ][ +  - ]:         19 :     ProgOpt* opt = new ProgOpt( helpname, "", flags, type );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     179 [ +  - ][ +  + ]:         19 :     if( value ) opt->storage = value;
         [ +  + ][ +  + ]
     180 [ +  - ][ +  - ]:         19 :     help_line help = std::make_pair( opt, helpstring );
         [ +  - ][ +  - ]
     181 [ +  - ][ +  - ]:         19 :     arg_help_strings.push_back( help );
         [ +  - ][ +  - ]
     182 [ +  - ][ +  - ]:         19 :     required_args[helpname] = opt;
         [ +  - ][ +  - ]
     183                 :         19 : }
     184                 :            : 
     185                 :            : template < typename T >
     186                 :          4 : void ProgOptions::addOptionalArgs( unsigned max_count, const std::string& helpname, const std::string& helpstring,
     187                 :            :                                    int flags )
     188                 :            : {
     189                 :            :     // If there was a previous one, we need to remove it
     190                 :            :     // because there can be only one.  If we didn't remove
     191                 :            :     // the old one then it would be treated as a required arg.
     192 [ #  # ][ -  + ]:          4 :     if( expect_optional_args )
         [ #  # ][ #  # ]
     193                 :            :     {
     194 [ #  # ][ #  # ]:          0 :         std::map< std::string, ProgOpt* >::iterator iter;
         [ #  # ][ #  # ]
     195 [ #  # ][ #  # ]:          0 :         iter = required_args.find( arg_help_strings[optional_args_position].second );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     196 [ #  # ][ #  # ]:          0 :         assert( iter != required_args.end() );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     197 [ #  # ][ #  # ]:          0 :         delete iter->second;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     198 [ #  # ][ #  # ]:          0 :         required_args.erase( iter );
         [ #  # ][ #  # ]
     199 [ #  # ][ #  # ]:          0 :         arg_help_strings.erase( arg_help_strings.begin() + optional_args_position );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     200                 :            :     }
     201                 :            : 
     202                 :          4 :     expect_optional_args   = true;
     203                 :          4 :     optional_args_position = arg_help_strings.size();
     204                 :          4 :     max_optional_args      = max_count;
     205                 :          4 :     addRequiredArg< T >( helpname, helpstring, 0, flags );
     206                 :          4 : }
     207                 :            : 
     208                 :          0 : void ProgOptions::addOptionHelpHeading( const std::string& s )
     209                 :            : {
     210 [ #  # ][ #  # ]:          0 :     option_help_strings.push_back( std::make_pair( (ProgOpt*)NULL, s ) );
     211                 :          0 : }
     212                 :            : 
     213                 :          0 : void ProgOptions::printVersion( std::ostream& out )
     214                 :            : {
     215                 :          0 :     out << progversion << std::endl;
     216                 :          0 : }
     217                 :            : 
     218                 :          0 : void ProgOptions::printHelp( std::ostream& out )
     219                 :            : {
     220                 :            : 
     221                 :            :     /* Print introductory help text */
     222 [ #  # ][ #  # ]:          0 :     if( !brief_help.empty() ) out << brief_help << std::endl;
                 [ #  # ]
     223 [ #  # ][ #  # ]:          0 :     for( std::vector< std::string >::iterator i = main_help.begin(); i != main_help.end(); ++i )
                 [ #  # ]
     224                 :            :     {
     225 [ #  # ][ #  # ]:          0 :         if( ( *i ).length() ) { out << std::endl << *i << std::endl; }
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     226                 :            :     }
     227                 :            : 
     228         [ #  # ]:          0 :     printUsage( out );
     229                 :            : 
     230                 :            :     // max number of characters to pad argument/option names with
     231                 :            :     // options with long names may exceed this, but will appear out of alignment in help text
     232                 :          0 :     const int max_padding = 20;
     233                 :            : 
     234                 :            :     /* List required arguments, with help text */
     235         [ #  # ]:          0 :     if( arg_help_strings.size() > 0 )
     236                 :            :     {
     237                 :            : 
     238                 :          0 :         int max_arg_namelen = 0;
     239                 :            : 
     240 [ #  # ][ #  # ]:          0 :         for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
                 [ #  # ]
     241                 :            :         {
     242 [ #  # ][ #  # ]:          0 :             max_arg_namelen = std::max( max_arg_namelen, (int)( ( *i ).first->longname.length() ) );
     243                 :            :         }
     244                 :            : 
     245         [ #  # ]:          0 :         max_arg_namelen = std::min( max_arg_namelen + 3, max_padding );
     246                 :            : 
     247 [ #  # ][ #  # ]:          0 :         out << "Arguments: " << std::endl;
     248                 :            : 
     249 [ #  # ][ #  # ]:          0 :         for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
                 [ #  # ]
     250                 :            :         {
     251         [ #  # ]:          0 :             ProgOpt* option   = ( *i ).first;
     252         [ #  # ]:          0 :             std::string& info = ( *i ).second;
     253                 :            : 
     254 [ #  # ][ #  # ]:          0 :             std::stringstream s;
     255 [ #  # ][ #  # ]:          0 :             s << "  " << option->longname;
     256 [ #  # ][ #  # ]:          0 :             out << std::setw( max_arg_namelen ) << std::left << s.str();
         [ #  # ][ #  # ]
                 [ #  # ]
     257 [ #  # ][ #  # ]:          0 :             out << ": " << info << std::endl;
                 [ #  # ]
     258                 :          0 :         }
     259                 :            :     }
     260                 :            : 
     261                 :            :     /* List options, with help text */
     262 [ #  # ][ #  # ]:          0 :     out << "Options: " << std::endl;
     263                 :          0 :     int max_option_prefix_len = 0;
     264                 :            : 
     265 [ #  # ][ #  # ]:          0 :     for( std::vector< help_line >::iterator i = option_help_strings.begin(); i != option_help_strings.end(); ++i )
                 [ #  # ]
     266                 :            :     {
     267         [ #  # ]:          0 :         ProgOpt* option   = ( *i ).first;
     268         [ #  # ]:          0 :         std::string& info = ( *i ).second;
     269                 :            : 
     270         [ #  # ]:          0 :         if( option )
     271                 :            :         {
     272                 :            : 
     273         [ #  # ]:          0 :             if( max_option_prefix_len == 0 )
     274                 :            :             {
     275                 :            :                 // iterate ahead in the option list to determine whitespace padding
     276                 :            :                 // stop if (*j).first is NULL, which indicates a help header message
     277 [ #  # ][ #  # ]:          0 :                 for( std::vector< help_line >::iterator j = i; j != option_help_strings.end() && ( *j ).first; ++j )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     278                 :            :                 {
     279 [ #  # ][ #  # ]:          0 :                     int len               = get_option_usage_prefix( *( ( *j ).first ) ).length();
     280         [ #  # ]:          0 :                     max_option_prefix_len = std::max( max_option_prefix_len, len );
     281                 :            :                 }
     282                 :            :             }
     283         [ #  # ]:          0 :             max_option_prefix_len     = std::min( max_option_prefix_len, max_padding );
     284         [ #  # ]:          0 :             std::string option_prefix = get_option_usage_prefix( *option );
     285                 :            : 
     286 [ #  # ][ #  # ]:          0 :             out << std::setw( max_option_prefix_len ) << std::left << option_prefix;
         [ #  # ][ #  # ]
     287         [ #  # ]:          0 :             out << ": ";
     288                 :            :         }
     289                 :            :         else
     290                 :            :         {
     291                 :            :             // no option: this is a help header.  Reset max name length.
     292                 :          0 :             max_option_prefix_len = 0;
     293                 :            :         }
     294 [ #  # ][ #  # ]:          0 :         out << info << std::endl;
     295                 :            :     }
     296                 :          0 : }
     297                 :            : 
     298                 :          0 : std::string ProgOptions::get_option_usage_prefix( const ProgOpt& option )
     299                 :            : {
     300                 :          0 :     bool has_shortname = option.shortname.length() > 0;
     301                 :          0 :     bool has_longname  = option.longname.length() > 0;
     302 [ #  # ][ #  # ]:          0 :     std::string argstr = option.get_argstring();
     303                 :            : 
     304 [ #  # ][ #  # ]:          0 :     std::stringstream s;
     305         [ #  # ]:          0 :     s << "  ";
     306         [ #  # ]:          0 :     if( has_shortname )
     307                 :            :     {
     308                 :            : 
     309 [ #  # ][ #  # ]:          0 :         s << "-" << option.shortname;
     310 [ #  # ][ #  # ]:          0 :         if( has_longname ) { s << " "; }
     311                 :            :     }
     312         [ #  # ]:          0 :     else if( option.flags & int_flag )
     313                 :            :     {
     314                 :            : 
     315         [ #  # ]:          0 :         s << "-<n>";
     316 [ #  # ][ #  # ]:          0 :         if( has_longname ) { s << " "; }
     317                 :            :     }
     318         [ #  # ]:          0 :     if( has_longname )
     319                 :            :     {
     320                 :            : 
     321 [ #  # ][ #  # ]:          0 :         if( has_shortname ) s << "[";
     322 [ #  # ][ #  # ]:          0 :         s << "--" << option.longname;
     323 [ #  # ][ #  # ]:          0 :         if( has_shortname ) s << "]";
     324                 :            :     }
     325                 :            : 
     326 [ #  # ][ #  # ]:          0 :     if( argstr.length() ) s << " <" << argstr << ">";
         [ #  # ][ #  # ]
     327         [ #  # ]:          0 :     return s.str();
     328                 :            : }
     329                 :            : 
     330                 :          0 : void ProgOptions::printUsage( std::ostream& out )
     331                 :            : {
     332                 :            : 
     333                 :          0 :     out << "Usage: " << progname << " --help | [options] ";
     334                 :            : 
     335         [ #  # ]:          0 :     for( size_t i = 0; i < arg_help_strings.size(); ++i )
     336                 :            :     {
     337 [ #  # ][ #  # ]:          0 :         if( !expect_optional_args || i != optional_args_position )
     338                 :          0 :             out << '<' << arg_help_strings[i].first->longname << "> ";
     339 [ #  # ][ #  # ]:          0 :         else if( 0 == max_optional_args || max_optional_args > 3 )
     340                 :          0 :             out << "[<" << arg_help_strings[i].first->longname << "> ...] ";
     341         [ #  # ]:          0 :         else if( 1 == max_optional_args )
     342                 :          0 :             out << "[" << arg_help_strings[i].first->longname << "] ";
     343                 :            :         else
     344         [ #  # ]:          0 :             for( unsigned j = 0; j < max_optional_args; ++j )
     345                 :          0 :                 out << "[" << arg_help_strings[i].first->longname << ( j + 1 ) << "] ";
     346                 :            :     }
     347                 :            : 
     348                 :          0 :     out << std::endl;
     349                 :          0 : }
     350                 :            : 
     351                 :         97 : ProgOpt* ProgOptions::lookup( const std::map< std::string, ProgOpt* >& table, const std::string& arg )
     352                 :            : {
     353         [ +  - ]:         97 :     std::map< std::string, ProgOpt* >::const_iterator it = table.find( arg );
     354 [ +  - ][ +  + ]:         97 :     if( it != table.end() )
     355         [ +  - ]:         80 :         return it->second;
     356 [ -  + ][ #  # ]:         34 :     else if( &table == &short_names && arg.size() == 1 && isdigit( arg[0] ) && !number_option_name.empty() &&
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ -  + ]
     357 [ #  # ][ #  # ]:         17 :              ( it = long_names.find( number_option_name ) ) != long_names.end() )
         [ #  # ][ #  # ]
         [ -  + ][ -  + ]
         [ -  + ][ +  - ]
           [ #  #  #  #  
             #  #  #  # ]
     358         [ #  # ]:          0 :         return it->second;
     359                 :            :     else
     360                 :         97 :         return 0;
     361                 :            : }
     362                 :            : 
     363                 :         22 : ProgOpt* ProgOptions::lookup_option( const std::string& namestring )
     364                 :            : {
     365 [ +  - ][ +  - ]:         44 :     std::string longname, shortname;
     366         [ +  - ]:         22 :     get_namestrings( namestring, &longname, &shortname );
     367                 :            : 
     368         [ +  - ]:         22 :     ProgOpt* opt = lookup( long_names, longname );
     369 [ +  + ][ +  - ]:         22 :     if( !opt ) opt = lookup( short_names, shortname );
     370                 :            : 
     371 [ -  + ][ #  # ]:         22 :     if( !opt ) { error( "Invalid option: " + namestring ); }
                 [ #  # ]
     372                 :            : 
     373                 :         22 :     return opt;
     374                 :            : }
     375                 :            : 
     376                 :          0 : void ProgOptions::error( const std::string& err )
     377                 :            : {
     378                 :          0 :     std::cerr << "Error: " << err << "\n" << std::endl;
     379                 :            :     ;
     380                 :          0 :     printUsage( std::cerr );
     381                 :          0 :     std::cerr << std::endl;
     382         [ #  # ]:          0 :     if( getenv( "MOAB_PROG_OPT_ABORT" ) ) abort();
     383                 :          0 :     std::exit( EXIT_FAILURE );
     384                 :            : }
     385                 :            : 
     386                 :            : // Copied from convert.cpp
     387                 :            : // Parse list of integer ranges
     388                 :            : // e.g. 1,2,5-10,12
     389                 :         12 : static bool parse_int_list( const char* string, std::vector< int >& results )
     390                 :            : {
     391                 :         12 :     bool okay   = true;
     392                 :         12 :     char* mystr = strdup( string );
     393         [ +  + ]:         40 :     for( const char* ptr = strtok( mystr, ", \t" ); ptr; ptr = strtok( 0, ", \t" ) )
     394                 :            :     {
     395                 :            :         char* endptr;
     396                 :         28 :         long val = strtol( ptr, &endptr, 0 );
     397         [ -  + ]:         28 :         if( endptr == ptr )
     398                 :            :         {
     399 [ #  # ][ #  # ]:          0 :             std::cerr << "Not an integer: \"" << ptr << '"' << std::endl;
         [ #  # ][ #  # ]
     400                 :          0 :             okay = false;
     401                 :          0 :             break;
     402                 :            :         }
     403                 :            : 
     404                 :         28 :         long val2 = val;
     405         [ +  + ]:         28 :         if( *endptr == '-' )
     406                 :            :         {
     407                 :          9 :             const char* sptr = endptr + 1;
     408                 :          9 :             val2             = strtol( sptr, &endptr, 0 );
     409         [ -  + ]:          9 :             if( endptr == sptr )
     410                 :            :             {
     411 [ #  # ][ #  # ]:          0 :                 std::cerr << "Not an integer: \"" << sptr << '"' << std::endl;
         [ #  # ][ #  # ]
     412                 :          0 :                 okay = false;
     413                 :          0 :                 break;
     414                 :            :             }
     415         [ -  + ]:          9 :             if( val2 < val )
     416                 :            :             {
     417 [ #  # ][ #  # ]:          0 :                 std::cerr << "Invalid id range: \"" << ptr << '"' << std::endl;
         [ #  # ][ #  # ]
     418                 :          0 :                 okay = false;
     419                 :          9 :                 break;
     420                 :            :             }
     421                 :            :         }
     422                 :            : 
     423         [ -  + ]:         28 :         if( *endptr )
     424                 :            :         {
     425                 :          0 :             okay = false;
     426                 :          0 :             break;
     427                 :            :         }
     428                 :            : 
     429         [ +  + ]:         82 :         for( ; val <= val2; ++val )
     430         [ +  - ]:         54 :             results.push_back( (int)val );
     431                 :            :     }
     432                 :            : 
     433                 :         12 :     free( mystr );
     434                 :         12 :     return okay;
     435                 :            : }
     436                 :            : 
     437                 :            : // Copied from convert.cpp
     438                 :            : // Replace '%' with MPI rank iff compiled with MPI
     439                 :          7 : static std::string do_rank_subst( const std::string& s )
     440                 :            : {
     441                 :            : #ifndef MOAB_HAVE_MPI
     442                 :            :     return s;
     443                 :            : #else
     444                 :            :     int rank, size;
     445 [ +  - ][ +  - ]:          7 :     if( MPI_SUCCESS != MPI_Comm_rank( MPI_COMM_WORLD, &rank ) || MPI_SUCCESS != MPI_Comm_size( MPI_COMM_WORLD, &size ) )
         [ +  - ][ -  + ]
                 [ -  + ]
     446         [ #  # ]:          0 :         return s;
     447                 :          7 :     int width = 1;
     448         [ -  + ]:          7 :     while( size > 10 )
     449                 :            :     {
     450                 :          0 :         size /= 10;
     451                 :          0 :         width++;
     452                 :            :     }
     453                 :            : 
     454                 :          7 :     size_t j = s.find( '%' );
     455 [ -  + ][ #  # ]:          7 :     if( j == std::string::npos ) return s;
     456                 :            : 
     457         [ +  - ]:          7 :     std::ostringstream st;
     458 [ +  - ][ +  - ]:          7 :     st << std::setfill( '0' );
     459 [ +  - ][ +  - ]:          7 :     st << s.substr( 0, j );
     460         [ +  - ]:          7 :     st << rank;
     461                 :            : 
     462                 :            :     size_t i;
     463         [ -  + ]:          7 :     while( ( i = s.find( '%', j + 1 ) ) != std::string::npos )
     464                 :            :     {
     465 [ #  # ][ #  # ]:          0 :         st << s.substr( j, i - j );
     466 [ #  # ][ #  # ]:          0 :         st << std::setw( width ) << rank;
                 [ #  # ]
     467                 :          0 :         j = i;
     468                 :            :     }
     469 [ +  - ][ +  - ]:          7 :     st << s.substr( j + 1 );
     470         [ +  - ]:          7 :     return st.str();
     471                 :            : #endif
     472                 :            : }
     473                 :            : 
     474                 :            : /**
     475                 :            :  * Check the input to a given option for correctness, converting it to its expected type (e.g. int)
     476                 :            :  * and storing the result to target, if target is non-NULL.
     477                 :            :  * @param option Used only in error messages to state which option could not be successfully
     478                 :            :  * converted
     479                 :            :  * @param arg_idx If non-NULL, evaluate the (*arg_idx)'th item in opt's args list
     480                 :            :  */
     481                 :         82 : bool ProgOptions::evaluate( const ProgOpt& opt, void* target, const std::string& option, unsigned* arg_idx )
     482                 :            : {
     483                 :            : 
     484         [ +  + ]:         82 :     unsigned idx = arg_idx ? *arg_idx : opt.args.size() - 1;
     485                 :            : 
     486   [ -  +  +  +  :         82 :     switch( opt.type )
                   +  - ]
     487                 :            :     {
     488                 :            :         case FLAG:
     489 [ #  # ][ #  # ]:          0 :             error( "Cannot evaluate a flag" );
     490                 :          0 :             break;
     491                 :            :         case INT: {
     492                 :            :             int temp;
     493         [ +  + ]:         14 :             int* i = target ? reinterpret_cast< int* >( target ) : &temp;
     494 [ -  + ][ #  # ]:         14 :             if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
         [ #  # ][ #  # ]
     495         [ +  - ]:         14 :             const char* arg = opt.args.at( idx ).c_str();
     496                 :            :             char* p;
     497                 :         14 :             *i = std::strtol( arg, &p, 0 );
     498 [ -  + ][ #  # ]:         14 :             if( *p != '\0' ) { error( "Bad integer argument '" + opt.args.at( idx ) + "' to " + option + " option." ); }
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     499                 :         14 :             return true;
     500                 :            :         }
     501                 :            :         case REAL: {
     502                 :            :             double temp;
     503         [ +  + ]:         14 :             double* i = target ? reinterpret_cast< double* >( target ) : &temp;
     504 [ -  + ][ #  # ]:         14 :             if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
         [ #  # ][ #  # ]
     505         [ +  - ]:         14 :             const char* arg = opt.args.at( idx ).c_str();
     506                 :            :             char* p;
     507                 :         14 :             *i = std::strtod( arg, &p );
     508 [ -  + ][ #  # ]:         14 :             if( *p != '\0' ) { error( "Bad real argument '" + opt.args.at( idx ) + "' to " + option + " option." ); }
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     509                 :         14 :             return true;
     510                 :            :         }
     511                 :            : 
     512                 :            :         case STRING: {
     513         [ +  - ]:         42 :             std::string temp;
     514         [ +  + ]:         42 :             std::string* i = target ? reinterpret_cast< std::string* >( target ) : &temp;
     515 [ -  + ][ #  # ]:         42 :             if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
         [ #  # ][ #  # ]
     516         [ +  + ]:         42 :             if( opt.flags & rank_subst )
     517 [ +  - ][ +  - ]:          7 :                 *i = do_rank_subst( opt.args.at( idx ) );
                 [ +  - ]
     518                 :            :             else
     519 [ +  - ][ +  - ]:         35 :                 *i = opt.args.at( idx );
     520                 :         42 :             return true;
     521                 :            :         }
     522                 :            : 
     523                 :            :         case INT_VECT: {
     524         [ +  - ]:         12 :             std::vector< int > temp;
     525         [ -  + ]:         12 :             std::vector< int >* i = target ? reinterpret_cast< std::vector< int >* >( target ) : &temp;
     526 [ +  - ][ +  - ]:         12 :             if( !parse_int_list( opt.args.at( idx ).c_str(), *i ) )
                 [ -  + ]
     527 [ #  # ][ #  # ]:          0 :                 error( "Bad integer list '" + opt.args.at( idx ) + "' to " + option + " option." );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     528                 :         12 :             return true;
     529                 :            :         }
     530                 :            :     }
     531                 :            : 
     532                 :         82 :     return false;
     533                 :            : }
     534                 :            : 
     535                 :            : template < typename T >
     536                 :         15 : bool ProgOptions::getOpt( const std::string& namestring, T* t )
     537                 :            : {
     538                 :            : 
     539                 :         15 :     ProgOpt* opt = lookup_option( namestring );
     540                 :            : 
     541 [ -  + ][ #  # ]:         15 :     if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ -  + ][ #  # ]
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     542                 :            : 
     543                 :            :     // This call to evaluate is inefficient, because opt was already evaluated when it was parsed.
     544 [ +  - ][ +  - ]:         15 :     if( opt->args.size() )
         [ +  - ][ +  - ]
                 [ #  # ]
     545                 :            :     {
     546 [ +  - ][ +  - ]:         15 :         if( t ) evaluate( *opt, t, "" );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ #  # ][ #  # ]
                 [ #  # ]
     547                 :         15 :         return true;
     548                 :            :     }
     549                 :            :     else
     550                 :         15 :         return false;
     551                 :            : }
     552                 :            : 
     553                 :            : template < typename T >
     554                 :          7 : void ProgOptions::getOptAllArgs( const std::string& namestring, std::vector< T >& values )
     555                 :            : {
     556                 :          7 :     ProgOpt* opt = lookup_option( namestring );
     557                 :            : 
     558                 :            :     // special case: if user asks for list of int, but argument
     559                 :            :     // was INT_VECT, concatenate all lists
     560 [ -  + ][ #  # ]:          7 :     if( get_opt_type< T >() == INT && opt->type == INT_VECT )
           [ -  +  -  + ]
                 [ #  # ]
           [ -  +  -  + ]
                 [ #  # ]
           [ -  +  +  - ]
         [ +  + ][ +  + ]
     561                 :            :     {
     562 [ #  # ][ #  # ]:          4 :         for( unsigned i = 0; i < opt->args.size(); ++i )
         [ #  # ][ +  + ]
     563 [ #  # ][ #  # ]:          3 :             evaluate( *opt, &values, "", &i );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
     564                 :          7 :         return;
     565                 :            :     }
     566                 :            : 
     567 [ -  + ][ #  # ]:          6 :     if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ -  + ][ #  # ]
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
     568                 :            : 
     569                 :          6 :     values.resize( opt->args.size() );
     570                 :            : 
     571                 :            :     // These calls to evaluate are inefficient, because the arguments were evaluated when they were
     572                 :            :     // parsed
     573 [ +  + ][ +  + ]:         21 :     for( unsigned i = 0; i < opt->args.size(); ++i )
         [ +  + ][ +  + ]
     574                 :            :     {
     575 [ +  - ][ +  - ]:         15 :         evaluate( *opt, &( values[i] ), "", &i );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     576                 :            :     }
     577                 :            : }
     578                 :            : 
     579                 :         11 : int ProgOptions::numOptSet( const std::string& namestring )
     580                 :            : {
     581 [ +  - ][ +  - ]:         22 :     std::string longname, shortname;
     582         [ +  - ]:         11 :     get_namestrings( namestring, &longname, &shortname );
     583                 :            : 
     584         [ +  - ]:         11 :     ProgOpt* opt = lookup( long_names, longname );
     585 [ +  + ][ +  - ]:         11 :     if( !opt ) opt = lookup( short_names, shortname );
     586                 :            : 
     587 [ -  + ][ #  # ]:         11 :     if( !opt ) { error( "Could not look up option: " + namestring ); }
                 [ #  # ]
     588                 :            : 
     589                 :         22 :     return opt->args.size();
     590                 :            : }
     591                 :            : 
     592                 :            : template < typename T >
     593                 :          9 : T ProgOptions::getReqArg( const std::string& namestring )
     594                 :            : {
     595                 :            : 
     596 [ +  - ][ +  - ]:          9 :     ProgOpt* opt = lookup( required_args, namestring );
     597                 :            : 
     598 [ -  + ][ #  # ]:          9 :     if( !opt ) { error( "Could not look up required arg: " + namestring ); }
         [ -  + ][ #  # ]
         [ -  + ][ #  # ]
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
     599                 :            : 
     600                 :            :     // if parseProgramOptions succeeded, we can assume each required arg has a value,
     601                 :            :     // so calling evaluate is valid
     602                 :          5 :     T value;
     603 [ +  - ][ +  - ]:          9 :     evaluate( *opt, &value, "" );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     604                 :          9 :     return value;
     605                 :            : }
     606                 :            : 
     607                 :            : template < typename T >
     608                 :          4 : void ProgOptions::getArgs( const std::string& namestring, std::vector< T >& values )
     609                 :            : {
     610                 :          4 :     ProgOpt* opt = lookup( required_args, namestring );
     611                 :            : 
     612 [ #  # ][ #  # ]:          4 :     if( !opt ) { error( "Could not look up required arg: " + namestring ); }
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     613                 :            : 
     614 [ #  # ][ #  # ]:          4 :     if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     615                 :            : 
     616                 :          4 :     values.resize( opt->args.size() );
     617                 :            : 
     618                 :            :     // These calls to evaluate are inefficient, because the arguments were evaluated when they were
     619                 :            :     // parsed
     620 [ #  # ][ +  + ]:          7 :     for( unsigned i = 0; i < opt->args.size(); ++i )
         [ #  # ][ #  # ]
     621                 :            :     {
     622 [ #  # ][ #  # ]:          3 :         evaluate( *opt, &( values[i] ), "", &i );
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     623                 :            :     }
     624                 :          4 : }
     625                 :            : 
     626                 :            : // Process parsed option.
     627                 :            : // Returns true if value is still expected
     628                 :            : // Should never return true if optional value is passed
     629                 :            : // \param arg Used for error messages only
     630                 :         34 : bool ProgOptions::process_option( ProgOpt* opt, std::string arg, const char* value )
     631                 :            : {
     632         [ -  + ]:         34 :     if( !opt )
     633                 :            :     {
     634         [ #  # ]:          0 :         if( arg == "--manpage" )
     635                 :            :         {
     636                 :          0 :             write_man_page( std::cout );
     637                 :          0 :             exit( 0 );
     638                 :            :         }
     639                 :            : 
     640         [ #  # ]:          0 :         error( "Unknown option: " + arg );
     641                 :            :     }
     642                 :            : 
     643         [ -  + ]:         34 :     if( opt->flags & help_flag )
     644                 :            :     {
     645                 :          0 :         printHelp( std::cout );
     646                 :          0 :         exit( EXIT_SUCCESS );
     647                 :            :     }
     648                 :            : 
     649         [ -  + ]:         34 :     if( opt->flags & version_flag )
     650                 :            :     {
     651                 :          0 :         printVersion( std::cout );
     652                 :          0 :         exit( EXIT_SUCCESS );
     653                 :            :     }
     654                 :            : 
     655         [ +  + ]:         34 :     if( opt->type != FLAG )
     656                 :            :     {
     657         [ +  + ]:         19 :         if( !value ) return true;
     658                 :            : 
     659 [ +  - ][ +  - ]:          5 :         opt->args.push_back( value );
     660                 :          5 :         evaluate( *opt, opt->storage, arg );
     661                 :            :     }
     662                 :            :     else
     663                 :            :     {
     664 [ -  + ][ #  # ]:         15 :         if( value ) { error( "Unexpected value for flag: " + arg ); }
     665                 :            : 
     666                 :            :         // do flag operations
     667         [ +  + ]:         15 :         if( opt->cancel_opt ) { opt->cancel_opt->args.clear(); }
     668         [ +  - ]:         15 :         if( opt->storage ) { *static_cast< bool* >( opt->storage ) = ( opt->flags & store_false ) ? false : true; }
     669 [ +  - ][ +  - ]:         15 :         opt->args.push_back( "" );
     670                 :            :     }
     671                 :            : 
     672                 :         34 :     return false;
     673                 :            : }
     674                 :            : 
     675                 :         25 : void ProgOptions::parseCommandLine( int argc, char* argv[] )
     676                 :            : {
     677                 :         25 :     const char* name = strrchr( argv[0], '/' );
     678         [ +  + ]:         25 :     if( name )
     679         [ +  - ]:          4 :         this->progname = ++name;
     680                 :            :     else
     681         [ +  - ]:         21 :         this->progname = argv[0];
     682                 :            : 
     683         [ +  - ]:         25 :     std::vector< const char* > args;
     684         [ +  - ]:         50 :     std::list< ProgOpt* > expected_vals;
     685                 :         25 :     bool no_more_flags = false;
     686                 :            : 
     687                 :            :     // Loop over all command line arguments
     688         [ +  + ]:         88 :     for( int i = 1; i < argc; ++i )
     689                 :            :     {
     690         [ +  - ]:         63 :         std::string arg( argv[i] );
     691         [ -  + ]:         63 :         if( arg.empty() ) continue;
     692                 :            : 
     693         [ +  + ]:         63 :         if( !expected_vals.empty() )
     694                 :            :         {
     695         [ +  - ]:         14 :             ProgOpt* opt = expected_vals.front();
     696         [ +  - ]:         14 :             expected_vals.pop_front();
     697         [ -  + ]:         14 :             assert( opt->type != FLAG );
     698         [ +  - ]:         14 :             opt->args.push_back( arg );
     699         [ +  - ]:         14 :             evaluate( *opt, opt->storage, arg );
     700                 :            :         }
     701 [ +  + ][ +  - ]:         49 :         else if( !no_more_flags && arg[0] == '-' )
         [ +  + ][ +  + ]
     702                 :            :         {
     703 [ +  + ][ +  - ]:         31 :             if( arg.length() > 2 && arg[1] == '-' )
         [ +  + ][ +  + ]
     704                 :            :             {  // long opt
     705                 :         17 :                 size_t eq = arg.find_first_of( '=' );
     706         [ +  + ]:         17 :                 if( eq != std::string::npos )
     707                 :            :                 {
     708 [ +  - ][ +  - ]:          5 :                     ProgOpt* opt = lookup( long_names, arg.substr( 2, eq - 2 ) );
     709 [ +  - ][ +  - ]:          5 :                     process_option( opt, arg, arg.substr( eq + 1 ).c_str() );
                 [ +  - ]
     710                 :            :                 }
     711                 :            :                 else
     712                 :            :                 {
     713 [ +  - ][ +  - ]:         12 :                     ProgOpt* opt = lookup( long_names, arg.substr( 2 ) );
     714 [ +  - ][ +  - ]:         17 :                     if( process_option( opt, arg ) ) expected_vals.push_back( opt );
         [ +  + ][ +  - ]
     715                 :            :                 }
     716                 :            :             }
     717 [ +  - ][ +  + ]:         14 :             else if( arg == "--" )
     718                 :            :             {  // --
     719                 :          2 :                 no_more_flags = true;
     720                 :            :             }
     721                 :            :             else
     722         [ +  + ]:         48 :                 for( size_t f = 1; f < arg.length(); ++f )
     723                 :            :                 {  // for each short opt
     724 [ +  - ][ +  - ]:         17 :                     ProgOpt* opt = lookup( short_names, std::string( 1, arg[f] ) );
                 [ +  - ]
     725 [ +  - ][ -  + ]:         17 :                     if( opt && ( opt->flags & int_flag ) )
     726                 :            :                     {
     727         [ #  # ]:          0 :                         const char val[] = { arg[f], 0 };
     728 [ #  # ][ #  # ]:          0 :                         process_option( opt, std::string( 1, arg[f] ), val );
                 [ #  # ]
     729                 :            :                     }
     730 [ +  - ][ +  - ]:         17 :                     else if( process_option( opt, std::string( 1, arg[f] ) ) )
         [ +  - ][ +  + ]
     731         [ +  - ]:         10 :                         expected_vals.push_back( opt );
     732                 :            :                 }
     733                 :            :         }
     734                 :            :         else
     735                 :            :         {
     736                 :            :             /* arguments */
     737 [ +  - ][ +  - ]:         63 :             args.push_back( argv[i] );
     738                 :            :         }
     739                 :         63 :     } /* End loop over inputs */
     740                 :            : 
     741                 :            :     // Print error if any missing values
     742         [ -  + ]:         25 :     if( !expected_vals.empty() )
     743                 :            :     {
     744 [ #  # ][ #  # ]:          0 :         error( "Missing value for option: -" + expected_vals.front()->shortname + ",--" +
         [ #  # ][ #  # ]
     745 [ #  # ][ #  # ]:          0 :                expected_vals.front()->longname );
     746                 :            :     }
     747                 :            : 
     748                 :            :     // Process non-option arguments
     749                 :         25 :     std::vector< help_line >::iterator arg_help_pos  = arg_help_strings.begin();
     750                 :         25 :     std::vector< const char* >::iterator arg_val_pos = args.begin();
     751                 :         25 :     std::vector< help_line >::iterator opt_args_pos  = arg_help_strings.end();
     752                 :         25 :     size_t min_required_args                         = required_args.size();
     753                 :         25 :     size_t max_required_args                         = required_args.size();
     754         [ +  + ]:         25 :     if( expect_optional_args )
     755                 :            :     {
     756                 :          4 :         min_required_args--;
     757         [ +  + ]:          4 :         if( max_optional_args )
     758                 :          2 :             max_required_args += max_optional_args;
     759                 :            :         else
     760                 :          2 :             max_required_args = std::numeric_limits< int >::max();
     761         [ +  - ]:          4 :         opt_args_pos = arg_help_pos + optional_args_position;
     762                 :            :     }
     763                 :            :     // check valid number of non-flag arguments
     764         [ -  + ]:         25 :     if( args.size() < min_required_args )
     765                 :            :     {
     766                 :          0 :         size_t missing_pos = args.size();
     767 [ #  # ][ #  # ]:          0 :         if( expect_optional_args && missing_pos >= optional_args_position ) ++missing_pos;
     768                 :            : 
     769         [ #  # ]:          0 :         const std::string& missed_arg = arg_help_strings[missing_pos].first->longname;
     770 [ #  # ][ #  # ]:          0 :         error( "Did not find required positional argument: " + missed_arg );
     771                 :            :     }
     772         [ -  + ]:         25 :     else if( args.size() > max_required_args )
     773                 :            :     {
     774 [ #  # ][ #  # ]:          0 :         error( "Unexpected argument: " + std::string( args[max_required_args] ) );
         [ #  # ][ #  # ]
     775                 :            :     }
     776                 :            : 
     777                 :            :     // proccess arguments up to the first optional argument
     778                 :            :     // (or all arguments if no optional args)
     779 [ +  - ][ +  + ]:         36 :     while( arg_help_pos != opt_args_pos )
     780                 :            :     {
     781         [ +  - ]:         11 :         ProgOpt* opt = arg_help_pos->first;
     782         [ +  - ]:         11 :         ++arg_help_pos;
     783 [ +  - ][ +  - ]:         11 :         opt->args.push_back( *arg_val_pos );
                 [ +  - ]
     784 [ +  - ][ +  - ]:         11 :         evaluate( *opt, opt->storage, *arg_val_pos );
                 [ +  - ]
     785         [ +  - ]:         11 :         ++arg_val_pos;
     786                 :            :     }
     787                 :            :     // process any optional args
     788 [ +  - ][ +  + ]:         25 :     if( arg_help_pos != arg_help_strings.end() )
     789                 :            :     {
     790 [ +  - ][ -  + ]:          4 :         assert( arg_help_pos == opt_args_pos );
     791                 :          4 :         size_t num_opt_args = args.size() + 1 - required_args.size();
     792         [ +  - ]:          4 :         ProgOpt* opt        = arg_help_pos->first;
     793         [ +  - ]:          4 :         ++arg_help_pos;
     794         [ +  + ]:          7 :         while( num_opt_args-- )
     795                 :            :         {
     796 [ +  - ][ +  - ]:          3 :             opt->args.push_back( *arg_val_pos );
                 [ +  - ]
     797 [ +  - ][ +  - ]:          3 :             evaluate( *opt, opt->storage, *arg_val_pos );
                 [ +  - ]
     798         [ +  - ]:          3 :             ++arg_val_pos;
     799                 :            :         }
     800                 :            :     }
     801                 :            :     // process any remaining args
     802 [ +  - ][ +  + ]:         29 :     while( arg_help_pos != arg_help_strings.end() )
     803                 :            :     {
     804 [ +  - ][ -  + ]:          4 :         assert( arg_val_pos != args.end() );
     805         [ +  - ]:          4 :         ProgOpt* opt = arg_help_pos->first;
     806         [ +  - ]:          4 :         ++arg_help_pos;
     807 [ +  - ][ +  - ]:          4 :         opt->args.push_back( *arg_val_pos );
                 [ +  - ]
     808 [ +  - ][ +  - ]:          4 :         evaluate( *opt, opt->storage, *arg_val_pos );
                 [ +  - ]
     809         [ +  - ]:          4 :         ++arg_val_pos;
     810                 :            :     }
     811 [ +  - ][ -  + ]:         50 :     assert( arg_val_pos == args.end() );
     812                 :         25 : }
     813                 :            : 
     814                 :          0 : void ProgOptions::write_man_page( std::ostream& s )
     815                 :            : {
     816                 :            :     // a leading '.' is a control character.  strip it if present.
     817         [ #  # ]:          0 :     std::string lprogname;
     818 [ #  # ][ #  # ]:          0 :     if( progname.empty() || progname[0] != '.' )
         [ #  # ][ #  # ]
     819         [ #  # ]:          0 :         lprogname = progname;
     820                 :            :     else
     821                 :            :     {
     822 [ #  # ][ #  # ]:          0 :         lprogname = progname.substr( 1 );
     823                 :            :     }
     824                 :            : 
     825                 :            :     // Manpage controls:
     826                 :            :     // .TH title
     827                 :            :     // .SH section
     828                 :            :     // .SS subsection
     829                 :            :     // .P  paragraph
     830                 :            :     // .HP hanging paragraph
     831                 :            :     // .B  bold
     832                 :            :     // .I  italic
     833                 :            :     // .B  bold
     834                 :            :     // .I  italic
     835                 :            :     // .RS begin indent
     836                 :            :     // .RE end indent
     837                 :            :     // .RB alternating roman and blold
     838                 :            :     // .BR alternating bold and roman
     839                 :            : 
     840                 :          0 :     std::vector< help_line >::iterator it;
     841         [ #  # ]:          0 :     std::set< ProgOpt* > skip_list;
     842                 :            : 
     843                 :            :     // start man page
     844 [ #  # ][ #  # ]:          0 :     s << std::endl << ".TH " << lprogname << " 1" << std::endl;
         [ #  # ][ #  # ]
                 [ #  # ]
     845                 :            : 
     846                 :            :     // write NAME section
     847 [ #  # ][ #  # ]:          0 :     s << std::endl << ".SH NAME" << std::endl << ".P " << std::endl << lprogname << " \\- ";
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     848 [ #  # ][ #  # ]:          0 :     if( brief_help.empty() && !main_help.empty() )
                 [ #  # ]
     849 [ #  # ][ #  # ]:          0 :         s << main_help.front();
     850                 :            :     else
     851         [ #  # ]:          0 :         s << brief_help;
     852 [ #  # ][ #  # ]:          0 :     s << std::endl << std::endl;
     853                 :            : 
     854                 :            :     // write SYNOPSIS section
     855 [ #  # ][ #  # ]:          0 :     s << std::endl << ".SH SYNOPSIS" << std::endl << ".HP" << std::endl << ".B \"" << lprogname << '"' << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     856 [ #  # ][ #  # ]:          0 :     for( it = option_help_strings.begin(); it != option_help_strings.end(); ++it )
                 [ #  # ]
     857                 :            :     {
     858 [ #  # ][ #  # ]:          0 :         if( !it->first || skip_list.find( it->first ) != skip_list.end() || it->first->longname == "help" ) continue;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
           [ #  #  #  # ]
     859                 :            : 
     860 [ #  # ][ #  # ]:          0 :         if( it->first->type == FLAG )
     861                 :            :         {
     862                 :          0 :             char c = '[';
     863         [ #  # ]:          0 :             s << ".RB";
     864 [ #  # ][ #  # ]:          0 :             if( !it->first->shortname.empty() )
     865                 :            :             {
     866 [ #  # ][ #  # ]:          0 :                 s << ' ' << c << " \"-" << it->first->shortname << '"';
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     867                 :          0 :                 c = '|';
     868                 :            :             }
     869 [ #  # ][ #  # ]:          0 :             if( !it->first->longname.empty() ) { s << ' ' << c << " \"--" << it->first->longname << '"'; }
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     870 [ #  # ][ #  # ]:          0 :             if( it->first->cancel_opt )
     871                 :            :             {
     872 [ #  # ][ #  # ]:          0 :                 skip_list.insert( it->first->cancel_opt );
     873 [ #  # ][ #  # ]:          0 :                 if( !it->first->cancel_opt->shortname.empty() )
     874 [ #  # ][ #  # ]:          0 :                     s << " | \"-" << it->first->cancel_opt->shortname << '"';
         [ #  # ][ #  # ]
     875 [ #  # ][ #  # ]:          0 :                 if( !it->first->cancel_opt->longname.empty() ) s << " | \"--" << it->first->cancel_opt->longname << '"';
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     876                 :            :             }
     877 [ #  # ][ #  # ]:          0 :             s << " ]" << std::endl;
     878                 :            :         }
     879 [ #  # ][ #  # ]:          0 :         else if( it->first->flags & int_flag )
     880                 :            :         {
     881 [ #  # ][ #  # ]:          0 :             s << ".RB [ - <n>| \"--" << it->first->longname << "\" \"=" << it->first->get_argstring() << "]\""
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     882         [ #  # ]:          0 :               << std::endl;
     883                 :            :         }
     884                 :            :         else
     885                 :            :         {
     886         [ #  # ]:          0 :             s << ".RB [ ";
     887 [ #  # ][ #  # ]:          0 :             if( !it->first->shortname.empty() )
     888 [ #  # ][ #  # ]:          0 :                 s << "\"-" << it->first->shortname << "\" \"\\ " << it->first->get_argstring();
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     889 [ #  # ][ #  # ]:          0 :             if( !it->first->shortname.empty() && !it->first->longname.empty() ) s << "|\" ";
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     890 [ #  # ][ #  # ]:          0 :             if( !it->first->longname.empty() )
     891 [ #  # ][ #  # ]:          0 :                 s << "\"--" << it->first->longname << "\" \"=" << it->first->get_argstring();
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     892 [ #  # ][ #  # ]:          0 :             s << "]\"" << std::endl;
     893                 :            :         }
     894                 :            :     }
     895 [ #  # ][ #  # ]:          0 :     for( it = arg_help_strings.begin(); it != arg_help_strings.end(); ++it )
                 [ #  # ]
     896                 :            :     {
     897 [ #  # ][ #  # ]:          0 :         if( !it->first ) continue;
     898                 :            : 
     899 [ #  # ][ #  # ]:          0 :         if( !expect_optional_args || (unsigned)( it - arg_help_strings.begin() ) != optional_args_position )
         [ #  # ][ #  # ]
           [ #  #  #  # ]
     900 [ #  # ][ #  # ]:          0 :             s << it->first->longname << ' ';
                 [ #  # ]
     901         [ #  # ]:          0 :         else if( 1 == max_optional_args )
     902 [ #  # ][ #  # ]:          0 :             s << '[' << it->first->longname << "] ";
         [ #  # ][ #  # ]
     903                 :            :         else
     904 [ #  # ][ #  # ]:          0 :             s << '[' << it->first->longname << " ...] ";
         [ #  # ][ #  # ]
     905                 :            :     }
     906         [ #  # ]:          0 :     s << std::endl;
     907 [ #  # ][ #  # ]:          0 :     s << ".HP" << std::endl << ".B \"" << lprogname << " -h|--help\"" << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     908                 :            : 
     909                 :            :     // write DESCRIPTION section
     910 [ #  # ][ #  # ]:          0 :     s << std::endl << ".SH DESCRIPTION" << std::endl;
                 [ #  # ]
     911 [ #  # ][ #  # ]:          0 :     if( main_help.empty() ) s << brief_help << std::endl;
                 [ #  # ]
     912         [ #  # ]:          0 :     for( size_t i = 0; i < main_help.size(); ++i )
     913                 :            :     {
     914         [ #  # ]:          0 :         const std::string::size_type n = main_help[i].size();
     915                 :          0 :         std::string::size_type j       = 0, k;
     916 [ #  # ][ #  # ]:          0 :         s << std::endl << ".P" << std::endl;
                 [ #  # ]
     917         [ #  # ]:          0 :         while( j != n )
     918                 :            :         {
     919 [ #  # ][ #  # ]:          0 :             if( main_help[i][j] == '\n' )
                 [ #  # ]
     920                 :            :             {
     921 [ #  # ][ #  # ]:          0 :                 s << std::endl << ".P" << std::endl;
                 [ #  # ]
     922                 :          0 :                 ++j;
     923                 :          0 :                 continue;
     924                 :            :             }
     925 [ #  # ][ #  # ]:          0 :             k = main_help[i].find( "\n", j );
     926         [ #  # ]:          0 :             if( k == std::string::npos ) k = n;
     927 [ #  # ][ #  # ]:          0 :             if( main_help[i][j] == '.' ) s << '\\';
         [ #  # ][ #  # ]
     928 [ #  # ][ #  # ]:          0 :             s << main_help[i].substr( j, k - j );
                 [ #  # ]
     929                 :          0 :             j = k;
     930                 :            :         }
     931                 :            :     }
     932                 :            : 
     933                 :            :     // write OPTIONS section
     934 [ #  # ][ #  # ]:          0 :     s << std::endl << ".SH OPTIONS" << std::endl;
                 [ #  # ]
     935 [ #  # ][ #  # ]:          0 :     for( it = arg_help_strings.begin(); it != arg_help_strings.end(); ++it )
                 [ #  # ]
     936                 :            :     {
     937 [ #  # ][ #  # ]:          0 :         if( it->first )
     938 [ #  # ][ #  # ]:          0 :             s << ".IP \"" << it->first->longname << '"' << std::endl << it->second << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     939                 :            :         else
     940 [ #  # ][ #  # ]:          0 :             s << ".SS " << it->first->longname << std::endl;
         [ #  # ][ #  # ]
     941                 :            :     }
     942 [ #  # ][ #  # ]:          0 :     for( it = option_help_strings.begin(); it != option_help_strings.end(); ++it )
                 [ #  # ]
     943                 :            :     {
     944 [ #  # ][ #  # ]:          0 :         if( !it->first )
     945                 :            :         {
     946 [ #  # ][ #  # ]:          0 :             s << ".SS " << it->second << std::endl;
         [ #  # ][ #  # ]
     947                 :          0 :             continue;
     948                 :            :         }
     949                 :            : 
     950         [ #  # ]:          0 :         s << ".IP \"";
     951 [ #  # ][ #  # ]:          0 :         if( it->first->longname.empty() )
     952 [ #  # ][ #  # ]:          0 :             s << "-" << it->first->shortname;
                 [ #  # ]
     953 [ #  # ][ #  # ]:          0 :         else if( it->first->shortname.empty() )
     954 [ #  # ][ #  # ]:          0 :             s << "--" << it->first->longname;
                 [ #  # ]
     955                 :            :         else
     956 [ #  # ][ #  # ]:          0 :             s << "-" << it->first->shortname << ", --" << it->first->longname;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     957 [ #  # ][ #  # ]:          0 :         s << '"' << std::endl << it->second << std::endl;
         [ #  # ][ #  # ]
                 [ #  # ]
     958                 :            :     }
     959         [ #  # ]:          0 :     s << std::endl;
     960                 :          0 : }
     961                 :            : 
     962                 :            : /* Ensure g++ instantiates the template types we expect to use */
     963                 :            : 
     964                 :            : #define DECLARE_OPTION_TYPE( T )                                                               \
     965                 :            :     template void ProgOptions::addOpt< T >( const std::string&, const std::string&, T*, int ); \
     966                 :            :     template bool ProgOptions::getOpt< T >( const std::string&, T* );
     967                 :            : 
     968                 :            : #define DECLARE_VALUED_OPTION_TYPE( T )                                                                       \
     969                 :            :     DECLARE_OPTION_TYPE( T )                                                                                  \
     970                 :            :     template void ProgOptions::getOptAllArgs< T >( const std::string&, std::vector< T >& );                   \
     971                 :            :     template void ProgOptions::addRequiredArg< T >( const std::string&, const std::string&, T*, int );        \
     972                 :            :     template void ProgOptions::addOptionalArgs< T >( unsigned, const std::string&, const std::string&, int ); \
     973                 :            :     template T ProgOptions::getReqArg< T >( const std::string& );                                             \
     974                 :            :     template void ProgOptions::getArgs< T >( const std::string&, std::vector< T >& );
     975                 :            : 
     976                 :            : DECLARE_OPTION_TYPE( void )
     977                 :            : DECLARE_VALUED_OPTION_TYPE( int )
     978                 :            : DECLARE_VALUED_OPTION_TYPE( double )
     979                 :            : DECLARE_VALUED_OPTION_TYPE( std::string )
     980 [ +  - ][ +  - ]:         20 : DECLARE_VALUED_OPTION_TYPE( std::vector< int > )

Generated by: LCOV version 1.11