00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "Teuchos_CommandLineProcessor.hpp"
00033 #include "Teuchos_TestForException.hpp"
00034
00035 #ifdef HAVE_MPI
00036 #include "mpi.h"
00037 #endif
00038
00039 namespace {
00040
00041 inline int my_max( int a, int b ) { return a > b ? a : b; }
00042
00043 std::string remove_quotes( const std::string& str )
00044 {
00045 if(str[0] != '\"')
00046 return str;
00047 return str.substr(1,str.size()-2);
00048 }
00049
00050 std::string add_quotes( const std::string& str )
00051 {
00052 if(str[0] == '\"')
00053 return str;
00054 return "\"" + str + "\"";
00055 }
00056
00057 }
00058
00059 namespace Teuchos {
00060
00061 CommandLineProcessor::CommandLineProcessor(
00062 bool throwExceptions
00063 ,bool recogniseAllOptions
00064 )
00065 :throwExceptions_(throwExceptions)
00066 ,recogniseAllOptions_(recogniseAllOptions)
00067 {}
00068
00069
00070
00071 void CommandLineProcessor::setOption(
00072 const char option_true[]
00073 ,const char option_false[]
00074 ,bool *option_val
00075 ,const char documentation[]
00076 )
00077 {
00078 TEST_FOR_EXCEPT(!(option_val!=NULL));
00079 options_list_[std::string(option_true)]
00080 = opt_val_val_t(OPT_BOOL_TRUE,option_val);
00081 options_list_[std::string(option_false)]
00082 = opt_val_val_t(OPT_BOOL_FALSE,option_val);
00083 options_documentation_list_.push_back(
00084 opt_doc_t(OPT_BOOL_TRUE,option_true,option_false,std::string(documentation?documentation:""),option_val) );
00085 }
00086
00087 void CommandLineProcessor::setOption(
00088 const char option_name[]
00089 ,int *option_val
00090 ,const char documentation[]
00091 )
00092 {
00093 TEST_FOR_EXCEPT(!(option_val!=NULL));
00094 options_list_[std::string(option_name)]
00095 = opt_val_val_t(OPT_INT,option_val);
00096 options_documentation_list_.push_back(
00097 opt_doc_t(OPT_INT,option_name,"",std::string(documentation?documentation:""),option_val) );
00098 }
00099
00100 void CommandLineProcessor::setOption(
00101 const char option_name[]
00102 ,double *option_val
00103 ,const char documentation[]
00104 )
00105 {
00106 TEST_FOR_EXCEPT(!(option_val!=NULL));
00107 options_list_[std::string(option_name)]
00108 = opt_val_val_t(OPT_DOUBLE,option_val);
00109 options_documentation_list_.push_back(
00110 opt_doc_t(OPT_DOUBLE,option_name,"",std::string(documentation?documentation:""),option_val) );
00111 }
00112
00113 void CommandLineProcessor::setOption(
00114 const char option_name[]
00115 ,std::string *option_val
00116 ,const char documentation[]
00117 )
00118 {
00119 TEST_FOR_EXCEPT(!(option_val!=NULL));
00120 options_list_[std::string(option_name)]
00121 = opt_val_val_t(OPT_STRING,option_val);
00122 options_documentation_list_.push_back(
00123 opt_doc_t(OPT_STRING,option_name,"",std::string(documentation?documentation:""),option_val) );
00124 }
00125
00126
00127
00128 CommandLineProcessor::EParseCommandLineReturn
00129 CommandLineProcessor::parse(
00130 int argc
00131 ,char* argv[]
00132 ,std::ostream *errout
00133 ) const
00134 {
00135 std::string opt_name;
00136 std::string opt_val_str;
00137 const std::string help_opt = "help";
00138 const std::string pause_opt = "pause-for-debugging";
00139 #ifdef HAVE_MPI
00140 int procRank = -1;
00141 #endif
00142 for( int i = 1; i < argc; ++i ) {
00143 bool gov_return = get_opt_val( argv[i], &opt_name, &opt_val_str );
00144 if( !gov_return ) {
00145 if(recogniseAllOptions()) {
00146 #ifdef HAVE_MPI
00147 if (procRank == 0)
00148 #endif
00149 print_bad_opt(i,argv,errout);
00150 return PARSE_UNRECOGNIZED_OPTION;
00151 }
00152 else {
00153 continue;
00154 }
00155 }
00156 if( opt_name == help_opt ) {
00157 if(errout) printHelpMessage( argv[0], *errout );
00158 return PARSE_HELP_PRINTED;
00159 }
00160 if( opt_name == pause_opt ) {
00161 #ifdef HAVE_MPI
00162 if(procRank < 0 ) MPI_Comm_rank( MPI_COMM_WORLD, &procRank );
00163 if(procRank == 0) {
00164 #endif
00165 std::cerr << "\nType 0 and press enter to continue : ";
00166 int dummy_int = 0;
00167 std::cin >> dummy_int;
00168 #ifdef HAVE_MPI
00169 }
00170 MPI_Barrier(MPI_COMM_WORLD);
00171 #endif
00172 continue;
00173 }
00174
00175 options_list_t::const_iterator itr = options_list_.find(opt_name);
00176 if( itr == options_list_.end() ) {
00177 #ifdef HAVE_MPI
00178 if(procRank == 0)
00179 #endif
00180 print_bad_opt(i,argv,errout);
00181 if( recogniseAllOptions() )
00182 return PARSE_UNRECOGNIZED_OPTION;
00183 else
00184 continue;
00185 }
00186
00187
00188 const opt_val_val_t &opt_val_val = (*itr).second;
00189 switch( opt_val_val.opt_type ) {
00190 case OPT_BOOL_TRUE:
00191 *(any_cast<bool*>(opt_val_val.opt_val)) = true;
00192 break;
00193 case OPT_BOOL_FALSE:
00194 *(any_cast<bool*>(opt_val_val.opt_val)) = false;
00195 break;
00196 case OPT_INT:
00197 *(any_cast<int*>(opt_val_val.opt_val)) = ::atoi(opt_val_str.c_str());
00198 break;
00199 case OPT_DOUBLE:
00200 *(any_cast<double*>(opt_val_val.opt_val)) = ::atof(opt_val_str.c_str());
00201 break;
00202 case OPT_STRING:
00203 *(any_cast<std::string*>(opt_val_val.opt_val)) = remove_quotes(opt_val_str);
00204 break;
00205 case OPT_ENUM_INT:
00206 if( !set_enum_value( i, argv, opt_name, any_cast<int>(opt_val_val.opt_val), remove_quotes(opt_val_str), errout ) )
00207 return PARSE_UNRECOGNIZED_OPTION;
00208 break;
00209 default:
00210 TEST_FOR_EXCEPT(true);
00211 }
00212 }
00213 return PARSE_SUCCESSFUL;
00214 }
00215
00216 void CommandLineProcessor::printHelpMessage( const char program_name[], std::ostream &out ) const
00217 {
00218 #ifdef HAVE_MPI
00219 int procRank = 0;
00220 int mpiInitialized;
00221 MPI_Initialized(&mpiInitialized);
00222 if(mpiInitialized) MPI_Comm_rank( MPI_COMM_WORLD, &procRank );
00223 if (procRank == 0) {
00224 #endif
00225 using std::setw;
00226 using std::endl;
00227
00228 const int opt_type_w = 8;
00229 const char spc_chars[] = " ";
00230
00231
00232 int opt_name_w = 19;
00233 options_documentation_list_t::const_iterator itr;
00234 for( itr = options_documentation_list_.begin(); itr != options_documentation_list_.end(); ++itr ) {
00235 opt_name_w = my_max(opt_name_w,itr->opt_name.length());
00236 if( itr->opt_type )
00237 opt_name_w = my_max(opt_name_w,itr->opt_name_false.length());
00238 }
00239 opt_name_w += 2;
00240
00241
00242 out
00243 << "Usage: " << program_name << " [options]\n"
00244 << spc_chars << "options:\n"
00245 << spc_chars
00246 << "--"
00247 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00248 << std::left << setw(opt_name_w) << "help"
00249 << std::left << setw(opt_type_w) << " "
00250 #else
00251 << std::setiosflags(std::ios::left) << setw(opt_name_w) << "help"
00252 << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00253 #endif
00254 << "Prints this help message"
00255 << endl
00256 << spc_chars
00257 << "--"
00258 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00259 << std::left << setw(opt_name_w) << "pause-for-debugging"
00260 << std::left << setw(opt_type_w) << " "
00261 #else
00262 << std::setiosflags(std::ios::left) << setw(opt_name_w) << "pause-for-debugging"
00263 << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00264 #endif
00265 << "Pauses for user input to allow attaching a debugger"
00266 << endl;
00267 for( itr = options_documentation_list_.begin(); itr != options_documentation_list_.end(); ++itr ) {
00268
00269 out
00270 << spc_chars
00271 << "--"
00272 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00273 << std::left << setw(opt_name_w) << itr->opt_name
00274 << std::left << setw(opt_type_w) << opt_type_str(itr->opt_type)
00275 #else
00276 << std::setiosflags(std::ios::left) << setw(opt_name_w) << itr->opt_name
00277 << std::setiosflags(std::ios::left) << setw(opt_type_w) << opt_type_str(itr->opt_type)
00278 #endif
00279 << ( itr->documentation.length() ? itr->documentation.c_str() : "No documentation" )
00280 << endl;
00281
00282 if( itr->opt_type == OPT_ENUM_INT ) {
00283 out
00284 << spc_chars
00285 << " "
00286 << setw(opt_name_w) << ""
00287 << setw(opt_type_w) << "";
00288 print_enum_opt_names( any_cast<int>(itr->default_val), out );
00289 out
00290 << endl;
00291 }
00292
00293 if( itr->opt_type == OPT_BOOL_TRUE ) {
00294 out
00295 << spc_chars
00296 << "--"
00297 << setw(opt_name_w) << itr->opt_name_false;
00298 }
00299 else {
00300 out
00301 << spc_chars
00302 << " "
00303 << setw(opt_name_w) << " ";
00304 }
00305 out
00306 << setw(opt_type_w) << " "
00307 << "(default: ";
00308 switch( itr->opt_type ) {
00309 case OPT_BOOL_TRUE:
00310 out << "--" << ( (*(any_cast<bool*>(itr->default_val))) ? itr->opt_name : itr->opt_name_false );
00311 break;
00312 case OPT_INT:
00313 case OPT_DOUBLE:
00314 case OPT_STRING:
00315 case OPT_ENUM_INT:
00316 out << "--" << itr->opt_name;
00317 break;
00318 default:
00319 TEST_FOR_EXCEPT(true);
00320 }
00321 switch( itr->opt_type ) {
00322 case OPT_BOOL_TRUE:
00323 break;
00324 case OPT_INT:
00325 out << "=" << (*(any_cast<int*>(itr->default_val)));
00326 break;
00327 case OPT_DOUBLE:
00328 out << "=" << (*(any_cast<double*>(itr->default_val)));
00329 break;
00330 case OPT_STRING:
00331 out << "=" << add_quotes(*(any_cast<std::string*>(itr->default_val)));
00332 break;
00333 case OPT_ENUM_INT:
00334 out << "=" << add_quotes(enum_opt_default_val_name(itr->opt_name,any_cast<int>(itr->default_val),&out));
00335 break;
00336 default:
00337 TEST_FOR_EXCEPT(true);
00338 }
00339 out << ")\n";
00340 }
00341 if(throwExceptions_)
00342 TEST_FOR_EXCEPTION( true, HelpPrinted, "Help message was printed" );
00343 #ifdef HAVE_MPI
00344 }
00345 #endif
00346 }
00347
00348
00349
00350 void CommandLineProcessor::setEnumOption(
00351 const char enum_option_name[]
00352 ,int *enum_option_val
00353 ,const int num_enum_opt_values
00354 ,const int enum_opt_values[]
00355 ,const char* enum_opt_names[]
00356 ,const char documentation[]
00357 )
00358 {
00359 TEST_FOR_EXCEPT(enum_option_val==NULL);
00360 TEST_FOR_EXCEPT(num_enum_opt_values<=0);
00361 TEST_FOR_EXCEPT(enum_opt_values==NULL);
00362 TEST_FOR_EXCEPT(enum_opt_names==NULL);
00363
00364 enum_opt_data_list_.push_back(
00365 enum_opt_data_t(enum_option_val,num_enum_opt_values,enum_opt_values,enum_opt_names)
00366 );
00367 const int opt_id = enum_opt_data_list_.size()-1;
00368 options_list_[std::string(enum_option_name)]
00369 = opt_val_val_t(OPT_ENUM_INT,opt_id);
00370 options_documentation_list_.push_back(
00371 opt_doc_t(OPT_ENUM_INT,enum_option_name,"",std::string(documentation?documentation:""),opt_id)
00372 );
00373 }
00374
00375 bool CommandLineProcessor::set_enum_value(
00376 int argv_i
00377 ,char* argv[]
00378 ,const std::string &enum_opt_name
00379 ,const int enum_id
00380 ,const std::string &enum_str_val
00381 ,std::ostream *errout
00382 ) const
00383 {
00384 const enum_opt_data_t
00385 &enum_opt_data = enum_opt_data_list_.at(enum_id);
00386 std::vector<std::string>::const_iterator
00387 itr_begin = enum_opt_data.enum_opt_names.begin(),
00388 itr_end = enum_opt_data.enum_opt_names.end(),
00389 itr = std::find( itr_begin, itr_end, enum_str_val );
00390 if( itr == itr_end ) {
00391 const int j = argv_i;
00392 #define CLP_ERR_MSG \
00393 "Error, the value \"" << enum_str_val << "\" for the " \
00394 << j<<(j==1?"st":(j==2?"nd":(j==3?"rd":"th"))) << " option --" \
00395 << enum_opt_name << " was not recognized (use --help)!"
00396 if(errout)
00397 *errout << std::endl << argv[0] << " : " << CLP_ERR_MSG << std::endl;
00398 if( throwExceptions() ) {
00399 TEST_FOR_EXCEPTION( true, std::invalid_argument, CLP_ERR_MSG );
00400 }
00401 else {
00402 return false;
00403 }
00404 #undef CLP_ERR_MSG
00405 }
00406 const int enum_opt_val_index = itr - itr_begin;
00407 *enum_opt_data.enum_option_val = enum_opt_data.enum_opt_values.at(enum_opt_val_index);
00408 return true;
00409 }
00410
00411 void CommandLineProcessor::print_enum_opt_names(
00412 const int enum_id
00413 ,std::ostream &out
00414 ) const
00415 {
00416 const enum_opt_data_t
00417 &enum_opt_data = enum_opt_data_list_.at(enum_id);
00418 typedef std::vector<string>::const_iterator itr_t;
00419 out << "Valid options:";
00420 for( itr_t itr = enum_opt_data.enum_opt_names.begin(); itr != enum_opt_data.enum_opt_names.end() ; ++itr ) {
00421 if( itr != enum_opt_data.enum_opt_names.begin() ) out << ",";
00422 out << " " << add_quotes(*itr);
00423 }
00424 }
00425
00426 std::string
00427 CommandLineProcessor::enum_opt_default_val_name(
00428 const std::string &enum_name
00429 ,const int enum_id
00430 ,std::ostream *errout
00431 ) const
00432 {
00433 const enum_opt_data_t
00434 &enum_opt_data = enum_opt_data_list_.at(enum_id);
00435 return enum_opt_data.enum_opt_names.at(
00436 find_enum_opt_index(
00437 enum_name,*enum_opt_data.enum_option_val,enum_opt_data,errout
00438 )
00439 );
00440 }
00441
00442 int CommandLineProcessor::find_enum_opt_index(
00443 const std::string &enum_opt_name
00444 ,const int opt_value
00445 ,const enum_opt_data_t &enum_data
00446 ,std::ostream *errout
00447 ) const
00448 {
00449 std::vector<int>::const_iterator
00450 itr_begin = enum_data.enum_opt_values.begin(),
00451 itr_end = enum_data.enum_opt_values.end(),
00452 itr = std::find( itr_begin, itr_end, opt_value );
00453 if( itr == itr_end ) {
00454 #define CLP_ERR_MSG \
00455 ( recogniseAllOptions() ? "Error" : "Warning" ) \
00456 << ", option --" << enum_opt_name << " was given an invalid " \
00457 "initial option value of " << opt_value << "!"
00458 if(errout)
00459 *errout << CLP_ERR_MSG << std::endl;
00460 if( throwExceptions() )
00461 TEST_FOR_EXCEPTION( true, std::invalid_argument, CLP_ERR_MSG );
00462 #undef CLP_ERR_MSG
00463 }
00464 return itr - itr_begin;
00465 }
00466
00467 bool CommandLineProcessor::get_opt_val(
00468 const char str[]
00469 ,std::string *opt_name
00470 ,std::string *opt_val_str
00471 ) const
00472 {
00473 const int len = strlen(str);
00474 if( len < 3 )
00475 return false;
00476 if( str[0] != '-' || str[1] != '-' )
00477 return false;
00478
00479 int equ_i;
00480 for( equ_i = 2; equ_i < len && str[equ_i] != '='; ++equ_i );
00481
00482 opt_name->assign( str + 2, equ_i-2 );
00483
00484 if( equ_i == len ) {
00485 *opt_val_str = "";
00486 }
00487 else {
00488 opt_val_str->assign( str + equ_i + 1, len - equ_i - 1 );
00489 }
00490 return true;
00491 }
00492
00493 void CommandLineProcessor::print_bad_opt(
00494 int argv_i
00495 ,char* argv[]
00496 ,std::ostream *errout
00497 ) const
00498 {
00499 const int j = argv_i;
00500 #define CLP_ERR_MSG \
00501 ( recogniseAllOptions() ? "Error" : "Warning" ) \
00502 << ", the " << j<<(j==1?"st":(j==2?"nd":(j==3?"rd":"th"))) \
00503 << " option \'" << argv[argv_i] << "\' was not recognized (use --help)!"
00504 if(errout)
00505 *errout << std::endl << argv[0] << " : " << CLP_ERR_MSG << std::endl;
00506 if( recogniseAllOptions() && throwExceptions() )
00507 TEST_FOR_EXCEPTION( true, UnrecognizedOption, CLP_ERR_MSG );
00508 #undef CLP_ERR_MSG
00509 }
00510
00511 }
00512
00513