MOAB: Mesh Oriented datABase  (version 5.2.1)
ProgOptions.cpp
Go to the documentation of this file.
00001 #include <iostream>
00002 #include <sstream>
00003 #include <iomanip>
00004 #include <cstdlib>
00005 #include <list>
00006 #include <limits>
00007 #include <set>
00008 #include <algorithm>
00009 
00010 #include <assert.h>
00011 #include <string.h>
00012 
00013 #include "moab/MOABConfig.h"
00014 #include "moab/ProgOptions.hpp"
00015 #ifdef MOAB_HAVE_MPI
00016 #include "moab_mpi.h"
00017 #endif
00018 
00019 enum OptType
00020 {
00021     FLAG = 0,
00022     INT,
00023     REAL,
00024     STRING,
00025     INT_VECT
00026 };
00027 
00028 template < typename T >
00029 inline static OptType get_opt_type();
00030 
00031 template <>
00032 OptType get_opt_type< void >()
00033 {
00034     return FLAG;
00035 }
00036 template <>
00037 OptType get_opt_type< int >()
00038 {
00039     return INT;
00040 }
00041 template <>
00042 OptType get_opt_type< double >()
00043 {
00044     return REAL;
00045 }
00046 template <>
00047 OptType get_opt_type< std::string >()
00048 {
00049     return STRING;
00050 }
00051 template <>
00052 OptType get_opt_type< std::vector< int > >()
00053 {
00054     return INT_VECT;
00055 }
00056 
00057 class ProgOpt
00058 {
00059 
00060     std::string shortname, longname;
00061     std::vector< std::string > args;
00062     OptType type;
00063     void* storage;
00064     int flags;
00065     ProgOpt* cancel_opt;
00066 
00067     const char* get_argstring() const
00068     {
00069         switch( type )
00070         {
00071             case INT:
00072                 return "int";
00073             case INT_VECT:
00074                 return "ints";
00075             case REAL:
00076                 return "val";
00077             case FLAG:
00078                 return "";
00079             default:
00080                 return "arg";
00081         }
00082     }
00083 
00084   public:
00085     ProgOpt( const std::string& longname_p, const std::string& shortname_p, int flags_p, OptType t = FLAG )
00086         : shortname( shortname_p ), longname( longname_p ), type( t ), storage( NULL ), flags( flags_p ),
00087           cancel_opt( NULL )
00088     {
00089     }
00090 
00091     friend class ProgOptions;
00092 };
00093 
00094 ProgOptions::ProgOptions( const std::string& helpstring, const std::string& briefhelp )
00095     : expect_optional_args( false ), optional_args_position( 0 ), max_optional_args( 0 )
00096 {
00097     brief_help = briefhelp;
00098     if( !helpstring.empty() ) main_help.push_back( helpstring );
00099     addOpt< void >( "help,h", "Show full help text", help_flag );
00100 }
00101 
00102 ProgOptions::~ProgOptions()
00103 {
00104     for( std::vector< help_line >::iterator i = option_help_strings.begin(); i != option_help_strings.end(); ++i )
00105     {
00106         if( ( *i ).first ) { delete( *i ).first; }
00107     }
00108 
00109     for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
00110     {
00111         delete( *i ).first;
00112     }
00113 }
00114 
00115 void ProgOptions::get_namestrings( const std::string& namestring, std::string* longname, std::string* shortname )
00116 {
00117     *shortname = "";
00118     *longname  = namestring;
00119 
00120     size_t idx = namestring.find_first_of( ',' );
00121     if( idx != namestring.npos )
00122     {
00123         *longname  = namestring.substr( 0, idx );
00124         *shortname = namestring.substr( idx + 1, namestring.npos );
00125     }
00126 }
00127 
00128 void ProgOptions::setVersion( const std::string& version_string, bool addFlag )
00129 {
00130     progversion = version_string;
00131     if( addFlag ) { addOpt< void >( "version", "Print version number and exit", version_flag ); }
00132 }
00133 
00134 template < typename T >
00135 void ProgOptions::addOpt( const std::string& namestring, const std::string& helpstring, T* value, int flags )
00136 {
00137 
00138     std::string shortname, longname;
00139     get_namestrings( namestring, &longname, &shortname );
00140 
00141     if( flags & int_flag )
00142     {  // short name is implicit for this flag
00143         if( !shortname.empty() ) error( "Requested short name with int_flag option" );
00144         if( get_opt_type< T >() != INT ) error( "Requested int_flag for non-integer option" );
00145         if( !number_option_name.empty() ) error( "Requested int_flag for multiple options" );
00146         number_option_name = longname;
00147     }
00148 
00149     ProgOpt* opt = new ProgOpt( longname, shortname, flags, get_opt_type< T >() );
00150     if( value ) opt->storage = value;
00151 
00152     if( longname.length() ) long_names[longname] = opt;
00153     if( shortname.length() ) short_names[shortname] = opt;
00154 
00155     help_line help = std::make_pair( opt, helpstring );
00156     option_help_strings.push_back( help );
00157 
00158     if( flags & add_cancel_opt )
00159     {
00160         std::string flag    = "no-" + ( longname.length() ? longname : shortname );
00161         ProgOpt* cancel_opt = new ProgOpt( flag, "", flags ^ ProgOptions::store_false, FLAG );
00162         if( value ) cancel_opt->storage = value;
00163 
00164         cancel_opt->cancel_opt       = opt;
00165         long_names[flag]             = cancel_opt;
00166         std::string clear_helpstring = "Clear previous " + flag.substr( 3, flag.npos ) + " flag";
00167         help                         = std::make_pair( cancel_opt, clear_helpstring );
00168         option_help_strings.push_back( help );
00169     }
00170 }
00171 
00172 template < typename T >
00173 void ProgOptions::addRequiredArg( const std::string& helpname, const std::string& helpstring, T* value, int flags )
00174 {
00175 
00176     OptType type = get_opt_type< T >();
00177 
00178     ProgOpt* opt = new ProgOpt( helpname, "", flags, type );
00179     if( value ) opt->storage = value;
00180     help_line help = std::make_pair( opt, helpstring );
00181     arg_help_strings.push_back( help );
00182     required_args[helpname] = opt;
00183 }
00184 
00185 template < typename T >
00186 void ProgOptions::addOptionalArgs( unsigned max_count, const std::string& helpname, const std::string& helpstring,
00187                                    int flags )
00188 {
00189     // If there was a previous one, we need to remove it
00190     // because there can be only one.  If we didn't remove
00191     // the old one then it would be treated as a required arg.
00192     if( expect_optional_args )
00193     {
00194         std::map< std::string, ProgOpt* >::iterator iter;
00195         iter = required_args.find( arg_help_strings[optional_args_position].second );
00196         assert( iter != required_args.end() );
00197         delete iter->second;
00198         required_args.erase( iter );
00199         arg_help_strings.erase( arg_help_strings.begin() + optional_args_position );
00200     }
00201 
00202     expect_optional_args   = true;
00203     optional_args_position = arg_help_strings.size();
00204     max_optional_args      = max_count;
00205     addRequiredArg< T >( helpname, helpstring, 0, flags );
00206 }
00207 
00208 void ProgOptions::addOptionHelpHeading( const std::string& s )
00209 {
00210     option_help_strings.push_back( std::make_pair( (ProgOpt*)NULL, s ) );
00211 }
00212 
00213 void ProgOptions::printVersion( std::ostream& out )
00214 {
00215     out << progversion << std::endl;
00216 }
00217 
00218 void ProgOptions::printHelp( std::ostream& out )
00219 {
00220 
00221     /* Print introductory help text */
00222     if( !brief_help.empty() ) out << brief_help << std::endl;
00223     for( std::vector< std::string >::iterator i = main_help.begin(); i != main_help.end(); ++i )
00224     {
00225         if( ( *i ).length() ) { out << std::endl << *i << std::endl; }
00226     }
00227 
00228     printUsage( out );
00229 
00230     // max number of characters to pad argument/option names with
00231     // options with long names may exceed this, but will appear out of alignment in help text
00232     const int max_padding = 20;
00233 
00234     /* List required arguments, with help text */
00235     if( arg_help_strings.size() > 0 )
00236     {
00237 
00238         int max_arg_namelen = 0;
00239 
00240         for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
00241         {
00242             max_arg_namelen = std::max( max_arg_namelen, (int)( ( *i ).first->longname.length() ) );
00243         }
00244 
00245         max_arg_namelen = std::min( max_arg_namelen + 3, max_padding );
00246 
00247         out << "Arguments: " << std::endl;
00248 
00249         for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
00250         {
00251             ProgOpt* option   = ( *i ).first;
00252             std::string& info = ( *i ).second;
00253 
00254             std::stringstream s;
00255             s << "  " << option->longname;
00256             out << std::setw( max_arg_namelen ) << std::left << s.str();
00257             out << ": " << info << std::endl;
00258         }
00259     }
00260 
00261     /* List options, with help text */
00262     out << "Options: " << std::endl;
00263     int max_option_prefix_len = 0;
00264 
00265     for( std::vector< help_line >::iterator i = option_help_strings.begin(); i != option_help_strings.end(); ++i )
00266     {
00267         ProgOpt* option   = ( *i ).first;
00268         std::string& info = ( *i ).second;
00269 
00270         if( option )
00271         {
00272 
00273             if( max_option_prefix_len == 0 )
00274             {
00275                 // iterate ahead in the option list to determine whitespace padding
00276                 // stop if (*j).first is NULL, which indicates a help header message
00277                 for( std::vector< help_line >::iterator j = i; j != option_help_strings.end() && ( *j ).first; ++j )
00278                 {
00279                     int len               = get_option_usage_prefix( *( ( *j ).first ) ).length();
00280                     max_option_prefix_len = std::max( max_option_prefix_len, len );
00281                 }
00282             }
00283             max_option_prefix_len     = std::min( max_option_prefix_len, max_padding );
00284             std::string option_prefix = get_option_usage_prefix( *option );
00285 
00286             out << std::setw( max_option_prefix_len ) << std::left << option_prefix;
00287             out << ": ";
00288         }
00289         else
00290         {
00291             // no option: this is a help header.  Reset max name length.
00292             max_option_prefix_len = 0;
00293         }
00294         out << info << std::endl;
00295     }
00296 }
00297 
00298 std::string ProgOptions::get_option_usage_prefix( const ProgOpt& option )
00299 {
00300     bool has_shortname = option.shortname.length() > 0;
00301     bool has_longname  = option.longname.length() > 0;
00302     std::string argstr = option.get_argstring();
00303 
00304     std::stringstream s;
00305     s << "  ";
00306     if( has_shortname )
00307     {
00308 
00309         s << "-" << option.shortname;
00310         if( has_longname ) { s << " "; }
00311     }
00312     else if( option.flags & int_flag )
00313     {
00314 
00315         s << "-<n>";
00316         if( has_longname ) { s << " "; }
00317     }
00318     if( has_longname )
00319     {
00320 
00321         if( has_shortname ) s << "[";
00322         s << "--" << option.longname;
00323         if( has_shortname ) s << "]";
00324     }
00325 
00326     if( argstr.length() ) s << " <" << argstr << ">";
00327     return s.str();
00328 }
00329 
00330 void ProgOptions::printUsage( std::ostream& out )
00331 {
00332 
00333     out << "Usage: " << progname << " --help | [options] ";
00334 
00335     for( size_t i = 0; i < arg_help_strings.size(); ++i )
00336     {
00337         if( !expect_optional_args || i != optional_args_position )
00338             out << '<' << arg_help_strings[i].first->longname << "> ";
00339         else if( 0 == max_optional_args || max_optional_args > 3 )
00340             out << "[<" << arg_help_strings[i].first->longname << "> ...] ";
00341         else if( 1 == max_optional_args )
00342             out << "[" << arg_help_strings[i].first->longname << "] ";
00343         else
00344             for( unsigned j = 0; j < max_optional_args; ++j )
00345                 out << "[" << arg_help_strings[i].first->longname << ( j + 1 ) << "] ";
00346     }
00347 
00348     out << std::endl;
00349 }
00350 
00351 ProgOpt* ProgOptions::lookup( const std::map< std::string, ProgOpt* >& table, const std::string& arg )
00352 {
00353     std::map< std::string, ProgOpt* >::const_iterator it = table.find( arg );
00354     if( it != table.end() )
00355         return it->second;
00356     else if( &table == &short_names && arg.size() == 1 && isdigit( arg[0] ) && !number_option_name.empty() &&
00357              ( it = long_names.find( number_option_name ) ) != long_names.end() )
00358         return it->second;
00359     else
00360         return 0;
00361 }
00362 
00363 ProgOpt* ProgOptions::lookup_option( const std::string& namestring )
00364 {
00365     std::string longname, shortname;
00366     get_namestrings( namestring, &longname, &shortname );
00367 
00368     ProgOpt* opt = lookup( long_names, longname );
00369     if( !opt ) opt = lookup( short_names, shortname );
00370 
00371     if( !opt ) { error( "Invalid option: " + namestring ); }
00372 
00373     return opt;
00374 }
00375 
00376 void ProgOptions::error( const std::string& err )
00377 {
00378     std::cerr << "Error: " << err << "\n" << std::endl;
00379     ;
00380     printUsage( std::cerr );
00381     std::cerr << std::endl;
00382     if( getenv( "MOAB_PROG_OPT_ABORT" ) ) abort();
00383     std::exit( EXIT_FAILURE );
00384 }
00385 
00386 // Copied from convert.cpp
00387 // Parse list of integer ranges
00388 // e.g. 1,2,5-10,12
00389 static bool parse_int_list( const char* string, std::vector< int >& results )
00390 {
00391     bool okay   = true;
00392     char* mystr = strdup( string );
00393     for( const char* ptr = strtok( mystr, ", \t" ); ptr; ptr = strtok( 0, ", \t" ) )
00394     {
00395         char* endptr;
00396         long val = strtol( ptr, &endptr, 0 );
00397         if( endptr == ptr )
00398         {
00399             std::cerr << "Not an integer: \"" << ptr << '"' << std::endl;
00400             okay = false;
00401             break;
00402         }
00403 
00404         long val2 = val;
00405         if( *endptr == '-' )
00406         {
00407             const char* sptr = endptr + 1;
00408             val2             = strtol( sptr, &endptr, 0 );
00409             if( endptr == sptr )
00410             {
00411                 std::cerr << "Not an integer: \"" << sptr << '"' << std::endl;
00412                 okay = false;
00413                 break;
00414             }
00415             if( val2 < val )
00416             {
00417                 std::cerr << "Invalid id range: \"" << ptr << '"' << std::endl;
00418                 okay = false;
00419                 break;
00420             }
00421         }
00422 
00423         if( *endptr )
00424         {
00425             okay = false;
00426             break;
00427         }
00428 
00429         for( ; val <= val2; ++val )
00430             results.push_back( (int)val );
00431     }
00432 
00433     free( mystr );
00434     return okay;
00435 }
00436 
00437 // Copied from convert.cpp
00438 // Replace '%' with MPI rank iff compiled with MPI
00439 static std::string do_rank_subst( const std::string& s )
00440 {
00441 #ifndef MOAB_HAVE_MPI
00442     return s;
00443 #else
00444     int rank, size;
00445     if( MPI_SUCCESS != MPI_Comm_rank( MPI_COMM_WORLD, &rank ) || MPI_SUCCESS != MPI_Comm_size( MPI_COMM_WORLD, &size ) )
00446         return s;
00447     int width = 1;
00448     while( size > 10 )
00449     {
00450         size /= 10;
00451         width++;
00452     }
00453 
00454     size_t j = s.find( '%' );
00455     if( j == std::string::npos ) return s;
00456 
00457     std::ostringstream st;
00458     st << std::setfill( '0' );
00459     st << s.substr( 0, j );
00460     st << rank;
00461 
00462     size_t i;
00463     while( ( i = s.find( '%', j + 1 ) ) != std::string::npos )
00464     {
00465         st << s.substr( j, i - j );
00466         st << std::setw( width ) << rank;
00467         j = i;
00468     }
00469     st << s.substr( j + 1 );
00470     return st.str();
00471 #endif
00472 }
00473 
00474 /**
00475  * Check the input to a given option for correctness, converting it to its expected type (e.g. int)
00476  * and storing the result to target, if target is non-NULL.
00477  * @param option Used only in error messages to state which option could not be successfully
00478  * converted
00479  * @param arg_idx If non-NULL, evaluate the (*arg_idx)'th item in opt's args list
00480  */
00481 bool ProgOptions::evaluate( const ProgOpt& opt, void* target, const std::string& option, unsigned* arg_idx )
00482 {
00483 
00484     unsigned idx = arg_idx ? *arg_idx : opt.args.size() - 1;
00485 
00486     switch( opt.type )
00487     {
00488         case FLAG:
00489             error( "Cannot evaluate a flag" );
00490             break;
00491         case INT: {
00492             int temp;
00493             int* i = target ? reinterpret_cast< int* >( target ) : &temp;
00494             if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
00495             const char* arg = opt.args.at( idx ).c_str();
00496             char* p;
00497             *i = std::strtol( arg, &p, 0 );
00498             if( *p != '\0' ) { error( "Bad integer argument '" + opt.args.at( idx ) + "' to " + option + " option." ); }
00499             return true;
00500         }
00501         case REAL: {
00502             double temp;
00503             double* i = target ? reinterpret_cast< double* >( target ) : &temp;
00504             if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
00505             const char* arg = opt.args.at( idx ).c_str();
00506             char* p;
00507             *i = std::strtod( arg, &p );
00508             if( *p != '\0' ) { error( "Bad real argument '" + opt.args.at( idx ) + "' to " + option + " option." ); }
00509             return true;
00510         }
00511 
00512         case STRING: {
00513             std::string temp;
00514             std::string* i = target ? reinterpret_cast< std::string* >( target ) : &temp;
00515             if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
00516             if( opt.flags & rank_subst )
00517                 *i = do_rank_subst( opt.args.at( idx ) );
00518             else
00519                 *i = opt.args.at( idx );
00520             return true;
00521         }
00522 
00523         case INT_VECT: {
00524             std::vector< int > temp;
00525             std::vector< int >* i = target ? reinterpret_cast< std::vector< int >* >( target ) : &temp;
00526             if( !parse_int_list( opt.args.at( idx ).c_str(), *i ) )
00527                 error( "Bad integer list '" + opt.args.at( idx ) + "' to " + option + " option." );
00528             return true;
00529         }
00530     }
00531 
00532     return false;
00533 }
00534 
00535 template < typename T >
00536 bool ProgOptions::getOpt( const std::string& namestring, T* t )
00537 {
00538 
00539     ProgOpt* opt = lookup_option( namestring );
00540 
00541     if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
00542 
00543     // This call to evaluate is inefficient, because opt was already evaluated when it was parsed.
00544     if( opt->args.size() )
00545     {
00546         if( t ) evaluate( *opt, t, "" );
00547         return true;
00548     }
00549     else
00550         return false;
00551 }
00552 
00553 template < typename T >
00554 void ProgOptions::getOptAllArgs( const std::string& namestring, std::vector< T >& values )
00555 {
00556     ProgOpt* opt = lookup_option( namestring );
00557 
00558     // special case: if user asks for list of int, but argument
00559     // was INT_VECT, concatenate all lists
00560     if( get_opt_type< T >() == INT && opt->type == INT_VECT )
00561     {
00562         for( unsigned i = 0; i < opt->args.size(); ++i )
00563             evaluate( *opt, &values, "", &i );
00564         return;
00565     }
00566 
00567     if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
00568 
00569     values.resize( opt->args.size() );
00570 
00571     // These calls to evaluate are inefficient, because the arguments were evaluated when they were
00572     // parsed
00573     for( unsigned i = 0; i < opt->args.size(); ++i )
00574     {
00575         evaluate( *opt, &( values[i] ), "", &i );
00576     }
00577 }
00578 
00579 int ProgOptions::numOptSet( const std::string& namestring )
00580 {
00581     std::string longname, shortname;
00582     get_namestrings( namestring, &longname, &shortname );
00583 
00584     ProgOpt* opt = lookup( long_names, longname );
00585     if( !opt ) opt = lookup( short_names, shortname );
00586 
00587     if( !opt ) { error( "Could not look up option: " + namestring ); }
00588 
00589     return opt->args.size();
00590 }
00591 
00592 template < typename T >
00593 T ProgOptions::getReqArg( const std::string& namestring )
00594 {
00595 
00596     ProgOpt* opt = lookup( required_args, namestring );
00597 
00598     if( !opt ) { error( "Could not look up required arg: " + namestring ); }
00599 
00600     // if parseProgramOptions succeeded, we can assume each required arg has a value,
00601     // so calling evaluate is valid
00602     T value;
00603     evaluate( *opt, &value, "" );
00604     return value;
00605 }
00606 
00607 template < typename T >
00608 void ProgOptions::getArgs( const std::string& namestring, std::vector< T >& values )
00609 {
00610     ProgOpt* opt = lookup( required_args, namestring );
00611 
00612     if( !opt ) { error( "Could not look up required arg: " + namestring ); }
00613 
00614     if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
00615 
00616     values.resize( opt->args.size() );
00617 
00618     // These calls to evaluate are inefficient, because the arguments were evaluated when they were
00619     // parsed
00620     for( unsigned i = 0; i < opt->args.size(); ++i )
00621     {
00622         evaluate( *opt, &( values[i] ), "", &i );
00623     }
00624 }
00625 
00626 // Process parsed option.
00627 // Returns true if value is still expected
00628 // Should never return true if optional value is passed
00629 // \param arg Used for error messages only
00630 bool ProgOptions::process_option( ProgOpt* opt, std::string arg, const char* value )
00631 {
00632     if( !opt )
00633     {
00634         if( arg == "--manpage" )
00635         {
00636             write_man_page( std::cout );
00637             exit( 0 );
00638         }
00639 
00640         error( "Unknown option: " + arg );
00641     }
00642 
00643     if( opt->flags & help_flag )
00644     {
00645         printHelp( std::cout );
00646         exit( EXIT_SUCCESS );
00647     }
00648 
00649     if( opt->flags & version_flag )
00650     {
00651         printVersion( std::cout );
00652         exit( EXIT_SUCCESS );
00653     }
00654 
00655     if( opt->type != FLAG )
00656     {
00657         if( !value ) return true;
00658 
00659         opt->args.push_back( value );
00660         evaluate( *opt, opt->storage, arg );
00661     }
00662     else
00663     {
00664         if( value ) { error( "Unexpected value for flag: " + arg ); }
00665 
00666         // do flag operations
00667         if( opt->cancel_opt ) { opt->cancel_opt->args.clear(); }
00668         if( opt->storage ) { *static_cast< bool* >( opt->storage ) = ( opt->flags & store_false ) ? false : true; }
00669         opt->args.push_back( "" );
00670     }
00671 
00672     return false;
00673 }
00674 
00675 void ProgOptions::parseCommandLine( int argc, char* argv[] )
00676 {
00677     const char* name = strrchr( argv[0], '/' );
00678     if( name )
00679         this->progname = ++name;
00680     else
00681         this->progname = argv[0];
00682 
00683     std::vector< const char* > args;
00684     std::list< ProgOpt* > expected_vals;
00685     bool no_more_flags = false;
00686 
00687     // Loop over all command line arguments
00688     for( int i = 1; i < argc; ++i )
00689     {
00690         std::string arg( argv[i] );
00691         if( arg.empty() ) continue;
00692 
00693         if( !expected_vals.empty() )
00694         {
00695             ProgOpt* opt = expected_vals.front();
00696             expected_vals.pop_front();
00697             assert( opt->type != FLAG );
00698             opt->args.push_back( arg );
00699             evaluate( *opt, opt->storage, arg );
00700         }
00701         else if( !no_more_flags && arg[0] == '-' )
00702         {
00703             if( arg.length() > 2 && arg[1] == '-' )
00704             {  // long opt
00705                 size_t eq = arg.find_first_of( '=' );
00706                 if( eq != std::string::npos )
00707                 {
00708                     ProgOpt* opt = lookup( long_names, arg.substr( 2, eq - 2 ) );
00709                     process_option( opt, arg, arg.substr( eq + 1 ).c_str() );
00710                 }
00711                 else
00712                 {
00713                     ProgOpt* opt = lookup( long_names, arg.substr( 2 ) );
00714                     if( process_option( opt, arg ) ) expected_vals.push_back( opt );
00715                 }
00716             }
00717             else if( arg == "--" )
00718             {  // --
00719                 no_more_flags = true;
00720             }
00721             else
00722                 for( size_t f = 1; f < arg.length(); ++f )
00723                 {  // for each short opt
00724                     ProgOpt* opt = lookup( short_names, std::string( 1, arg[f] ) );
00725                     if( opt && ( opt->flags & int_flag ) )
00726                     {
00727                         const char val[] = { arg[f], 0 };
00728                         process_option( opt, std::string( 1, arg[f] ), val );
00729                     }
00730                     else if( process_option( opt, std::string( 1, arg[f] ) ) )
00731                         expected_vals.push_back( opt );
00732                 }
00733         }
00734         else
00735         {
00736             /* arguments */
00737             args.push_back( argv[i] );
00738         }
00739     } /* End loop over inputs */
00740 
00741     // Print error if any missing values
00742     if( !expected_vals.empty() )
00743     {
00744         error( "Missing value for option: -" + expected_vals.front()->shortname + ",--" +
00745                expected_vals.front()->longname );
00746     }
00747 
00748     // Process non-option arguments
00749     std::vector< help_line >::iterator arg_help_pos  = arg_help_strings.begin();
00750     std::vector< const char* >::iterator arg_val_pos = args.begin();
00751     std::vector< help_line >::iterator opt_args_pos  = arg_help_strings.end();
00752     size_t min_required_args                         = required_args.size();
00753     size_t max_required_args                         = required_args.size();
00754     if( expect_optional_args )
00755     {
00756         min_required_args--;
00757         if( max_optional_args )
00758             max_required_args += max_optional_args;
00759         else
00760             max_required_args = std::numeric_limits< int >::max();
00761         opt_args_pos = arg_help_pos + optional_args_position;
00762     }
00763     // check valid number of non-flag arguments
00764     if( args.size() < min_required_args )
00765     {
00766         size_t missing_pos = args.size();
00767         if( expect_optional_args && missing_pos >= optional_args_position ) ++missing_pos;
00768 
00769         const std::string& missed_arg = arg_help_strings[missing_pos].first->longname;
00770         error( "Did not find required positional argument: " + missed_arg );
00771     }
00772     else if( args.size() > max_required_args )
00773     {
00774         error( "Unexpected argument: " + std::string( args[max_required_args] ) );
00775     }
00776 
00777     // proccess arguments up to the first optional argument
00778     // (or all arguments if no optional args)
00779     while( arg_help_pos != opt_args_pos )
00780     {
00781         ProgOpt* opt = arg_help_pos->first;
00782         ++arg_help_pos;
00783         opt->args.push_back( *arg_val_pos );
00784         evaluate( *opt, opt->storage, *arg_val_pos );
00785         ++arg_val_pos;
00786     }
00787     // process any optional args
00788     if( arg_help_pos != arg_help_strings.end() )
00789     {
00790         assert( arg_help_pos == opt_args_pos );
00791         size_t num_opt_args = args.size() + 1 - required_args.size();
00792         ProgOpt* opt        = arg_help_pos->first;
00793         ++arg_help_pos;
00794         while( num_opt_args-- )
00795         {
00796             opt->args.push_back( *arg_val_pos );
00797             evaluate( *opt, opt->storage, *arg_val_pos );
00798             ++arg_val_pos;
00799         }
00800     }
00801     // process any remaining args
00802     while( arg_help_pos != arg_help_strings.end() )
00803     {
00804         assert( arg_val_pos != args.end() );
00805         ProgOpt* opt = arg_help_pos->first;
00806         ++arg_help_pos;
00807         opt->args.push_back( *arg_val_pos );
00808         evaluate( *opt, opt->storage, *arg_val_pos );
00809         ++arg_val_pos;
00810     }
00811     assert( arg_val_pos == args.end() );
00812 }
00813 
00814 void ProgOptions::write_man_page( std::ostream& s )
00815 {
00816     // a leading '.' is a control character.  strip it if present.
00817     std::string lprogname;
00818     if( progname.empty() || progname[0] != '.' )
00819         lprogname = progname;
00820     else
00821     {
00822         lprogname = progname.substr( 1 );
00823     }
00824 
00825     // Manpage controls:
00826     // .TH title
00827     // .SH section
00828     // .SS subsection
00829     // .P  paragraph
00830     // .HP hanging paragraph
00831     // .B  bold
00832     // .I  italic
00833     // .B  bold
00834     // .I  italic
00835     // .RS begin indent
00836     // .RE end indent
00837     // .RB alternating roman and blold
00838     // .BR alternating bold and roman
00839 
00840     std::vector< help_line >::iterator it;
00841     std::set< ProgOpt* > skip_list;
00842 
00843     // start man page
00844     s << std::endl << ".TH " << lprogname << " 1" << std::endl;
00845 
00846     // write NAME section
00847     s << std::endl << ".SH NAME" << std::endl << ".P " << std::endl << lprogname << " \\- ";
00848     if( brief_help.empty() && !main_help.empty() )
00849         s << main_help.front();
00850     else
00851         s << brief_help;
00852     s << std::endl << std::endl;
00853 
00854     // write SYNOPSIS section
00855     s << std::endl << ".SH SYNOPSIS" << std::endl << ".HP" << std::endl << ".B \"" << lprogname << '"' << std::endl;
00856     for( it = option_help_strings.begin(); it != option_help_strings.end(); ++it )
00857     {
00858         if( !it->first || skip_list.find( it->first ) != skip_list.end() || it->first->longname == "help" ) continue;
00859 
00860         if( it->first->type == FLAG )
00861         {
00862             char c = '[';
00863             s << ".RB";
00864             if( !it->first->shortname.empty() )
00865             {
00866                 s << ' ' << c << " \"-" << it->first->shortname << '"';
00867                 c = '|';
00868             }
00869             if( !it->first->longname.empty() ) { s << ' ' << c << " \"--" << it->first->longname << '"'; }
00870             if( it->first->cancel_opt )
00871             {
00872                 skip_list.insert( it->first->cancel_opt );
00873                 if( !it->first->cancel_opt->shortname.empty() )
00874                     s << " | \"-" << it->first->cancel_opt->shortname << '"';
00875                 if( !it->first->cancel_opt->longname.empty() ) s << " | \"--" << it->first->cancel_opt->longname << '"';
00876             }
00877             s << " ]" << std::endl;
00878         }
00879         else if( it->first->flags & int_flag )
00880         {
00881             s << ".RB [ - <n>| \"--" << it->first->longname << "\" \"=" << it->first->get_argstring() << "]\""
00882               << std::endl;
00883         }
00884         else
00885         {
00886             s << ".RB [ ";
00887             if( !it->first->shortname.empty() )
00888                 s << "\"-" << it->first->shortname << "\" \"\\ " << it->first->get_argstring();
00889             if( !it->first->shortname.empty() && !it->first->longname.empty() ) s << "|\" ";
00890             if( !it->first->longname.empty() )
00891                 s << "\"--" << it->first->longname << "\" \"=" << it->first->get_argstring();
00892             s << "]\"" << std::endl;
00893         }
00894     }
00895     for( it = arg_help_strings.begin(); it != arg_help_strings.end(); ++it )
00896     {
00897         if( !it->first ) continue;
00898 
00899         if( !expect_optional_args || (unsigned)( it - arg_help_strings.begin() ) != optional_args_position )
00900             s << it->first->longname << ' ';
00901         else if( 1 == max_optional_args )
00902             s << '[' << it->first->longname << "] ";
00903         else
00904             s << '[' << it->first->longname << " ...] ";
00905     }
00906     s << std::endl;
00907     s << ".HP" << std::endl << ".B \"" << lprogname << " -h|--help\"" << std::endl;
00908 
00909     // write DESCRIPTION section
00910     s << std::endl << ".SH DESCRIPTION" << std::endl;
00911     if( main_help.empty() ) s << brief_help << std::endl;
00912     for( size_t i = 0; i < main_help.size(); ++i )
00913     {
00914         const std::string::size_type n = main_help[i].size();
00915         std::string::size_type j       = 0, k;
00916         s << std::endl << ".P" << std::endl;
00917         while( j != n )
00918         {
00919             if( main_help[i][j] == '\n' )
00920             {
00921                 s << std::endl << ".P" << std::endl;
00922                 ++j;
00923                 continue;
00924             }
00925             k = main_help[i].find( "\n", j );
00926             if( k == std::string::npos ) k = n;
00927             if( main_help[i][j] == '.' ) s << '\\';
00928             s << main_help[i].substr( j, k - j );
00929             j = k;
00930         }
00931     }
00932 
00933     // write OPTIONS section
00934     s << std::endl << ".SH OPTIONS" << std::endl;
00935     for( it = arg_help_strings.begin(); it != arg_help_strings.end(); ++it )
00936     {
00937         if( it->first )
00938             s << ".IP \"" << it->first->longname << '"' << std::endl << it->second << std::endl;
00939         else
00940             s << ".SS " << it->first->longname << std::endl;
00941     }
00942     for( it = option_help_strings.begin(); it != option_help_strings.end(); ++it )
00943     {
00944         if( !it->first )
00945         {
00946             s << ".SS " << it->second << std::endl;
00947             continue;
00948         }
00949 
00950         s << ".IP \"";
00951         if( it->first->longname.empty() )
00952             s << "-" << it->first->shortname;
00953         else if( it->first->shortname.empty() )
00954             s << "--" << it->first->longname;
00955         else
00956             s << "-" << it->first->shortname << ", --" << it->first->longname;
00957         s << '"' << std::endl << it->second << std::endl;
00958     }
00959     s << std::endl;
00960 }
00961 
00962 /* Ensure g++ instantiates the template types we expect to use */
00963 
00964 #define DECLARE_OPTION_TYPE( T )                                                               \
00965     template void ProgOptions::addOpt< T >( const std::string&, const std::string&, T*, int ); \
00966     template bool ProgOptions::getOpt< T >( const std::string&, T* );
00967 
00968 #define DECLARE_VALUED_OPTION_TYPE( T )                                                                       \
00969     DECLARE_OPTION_TYPE( T )                                                                                  \
00970     template void ProgOptions::getOptAllArgs< T >( const std::string&, std::vector< T >& );                   \
00971     template void ProgOptions::addRequiredArg< T >( const std::string&, const std::string&, T*, int );        \
00972     template void ProgOptions::addOptionalArgs< T >( unsigned, const std::string&, const std::string&, int ); \
00973     template T ProgOptions::getReqArg< T >( const std::string& );                                             \
00974     template void ProgOptions::getArgs< T >( const std::string&, std::vector< T >& );
00975 
00976 DECLARE_OPTION_TYPE( void )
00977 DECLARE_VALUED_OPTION_TYPE( int )
00978 DECLARE_VALUED_OPTION_TYPE( double )
00979 DECLARE_VALUED_OPTION_TYPE( std::string )
00980 DECLARE_VALUED_OPTION_TYPE( std::vector< int > )
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines