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