cgma
|
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>)