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_GlobalMPISession.hpp"
00034 #include "Teuchos_VerboseObject.hpp"
00035 #include "Teuchos_TestForException.hpp"
00036
00037 namespace {
00038
00039 inline int my_max( int a, int b ) { return a > b ? a : b; }
00040
00041 std::string remove_quotes( const std::string& str )
00042 {
00043 if(str[0] != '\"')
00044 return str;
00045 return str.substr(1,str.size()-2);
00046 }
00047
00048 std::string add_quotes( const std::string& str )
00049 {
00050 if(str[0] == '\"')
00051 return str;
00052 return "\"" + str + "\"";
00053 }
00054
00055 }
00056
00057 namespace Teuchos {
00058
00059 const bool CommandLineProcessor::output_all_front_matter_default_(false);
00060 const bool CommandLineProcessor::output_show_line_prefix_default_(false);
00061 const bool CommandLineProcessor::output_show_tab_count_default_(false);
00062 const bool CommandLineProcessor::output_show_proc_rank_default_(false);
00063 const int CommandLineProcessor::output_to_root_rank_only_default_(0);
00064
00065 CommandLineProcessor::CommandLineProcessor(
00066 bool throwExceptions
00067 ,bool recogniseAllOptions
00068 ,bool addOutputSetupOptions
00069 )
00070 :throwExceptions_(throwExceptions)
00071 ,recogniseAllOptions_(recogniseAllOptions)
00072 ,addOutputSetupOptions_(addOutputSetupOptions)
00073 ,output_all_front_matter_(output_all_front_matter_default_)
00074 ,output_show_line_prefix_(output_show_line_prefix_default_)
00075 ,output_show_tab_count_(output_show_tab_count_default_)
00076 ,output_show_proc_rank_(output_show_proc_rank_default_)
00077 ,output_to_root_rank_only_(output_to_root_rank_only_default_)
00078 ,added_extra_output_setup_options_(false)
00079 ,in_add_extra_output_setup_options_(false)
00080 {}
00081
00082
00083
00084 void CommandLineProcessor::setDocString( const char doc_string[] )
00085 {
00086 doc_string_ = doc_string;
00087 }
00088
00089 void CommandLineProcessor::setOption(
00090 const char option_true[]
00091 ,const char option_false[]
00092 ,bool *option_val
00093 ,const char documentation[]
00094 )
00095 {
00096 add_extra_output_setup_options();
00097 TEST_FOR_EXCEPT(!(option_val!=NULL));
00098 options_list_[std::string(option_true)]
00099 = opt_val_val_t(OPT_BOOL_TRUE,any(option_val),false);
00100 options_list_[std::string(option_false)]
00101 = opt_val_val_t(OPT_BOOL_FALSE,any(option_val),false);
00102 options_documentation_list_.push_back(
00103 opt_doc_t(OPT_BOOL_TRUE,option_true,option_false,std::string(documentation?documentation:""),any(option_val)) );
00104 }
00105
00106 void CommandLineProcessor::setOption(
00107 const char option_name[]
00108 ,int *option_val
00109 ,const char documentation[]
00110 ,const bool required
00111 )
00112 {
00113 add_extra_output_setup_options();
00114 TEST_FOR_EXCEPT(!(option_val!=NULL));
00115 options_list_[std::string(option_name)]
00116 = opt_val_val_t(OPT_INT,any(option_val),required);
00117 options_documentation_list_.push_back(
00118 opt_doc_t(OPT_INT,option_name,"",std::string(documentation?documentation:""),any(option_val)) );
00119 }
00120
00121 void CommandLineProcessor::setOption(
00122 const char option_name[]
00123 ,double *option_val
00124 ,const char documentation[]
00125 ,const bool required
00126 )
00127 {
00128 add_extra_output_setup_options();
00129 TEST_FOR_EXCEPT(!(option_val!=NULL));
00130 options_list_[std::string(option_name)]
00131 = opt_val_val_t(OPT_DOUBLE,any(option_val),required);
00132 options_documentation_list_.push_back(
00133 opt_doc_t(OPT_DOUBLE,option_name,"",std::string(documentation?documentation:""),any(option_val)) );
00134 }
00135
00136 void CommandLineProcessor::setOption(
00137 const char option_name[]
00138 ,std::string *option_val
00139 ,const char documentation[]
00140 ,const bool required
00141 )
00142 {
00143 add_extra_output_setup_options();
00144 TEST_FOR_EXCEPT(!(option_val!=NULL));
00145 options_list_[std::string(option_name)]
00146 = opt_val_val_t(OPT_STRING,any(option_val),required);
00147 options_documentation_list_.push_back(
00148 opt_doc_t(OPT_STRING,option_name,"",std::string(documentation?documentation:""),any(option_val)) );
00149 }
00150
00151
00152
00153 CommandLineProcessor::EParseCommandLineReturn
00154 CommandLineProcessor::parse(
00155 int argc
00156 ,char* argv[]
00157 ,std::ostream *errout
00158 ) const
00159 {
00160 add_extra_output_setup_options();
00161 std::string opt_name;
00162 std::string opt_val_str;
00163 const std::string echo_cl_opt = "echo-command-line";
00164 const std::string help_opt = "help";
00165 const std::string pause_opt = "pause-for-debugging";
00166 int procRank = GlobalMPISession::getRank();
00167 for( int i = 1; i < argc; ++i ) {
00168 bool gov_return = get_opt_val( argv[i], &opt_name, &opt_val_str );
00169 if( !gov_return ) {
00170 if(recogniseAllOptions()) {
00171 if(procRank == 0)
00172 print_bad_opt(i,argv,errout);
00173 return PARSE_UNRECOGNIZED_OPTION;
00174 }
00175 else {
00176 continue;
00177 }
00178 }
00179 if( opt_name == echo_cl_opt ) {
00180 if(errout && procRank == 0) {
00181 *errout << "\nEchoing the command-line:\n\n";
00182 for( int i = 0; i < argc; ++i )
00183 *errout << argv[i] << " ";
00184 *errout << "\n\n";
00185 }
00186 continue;
00187 }
00188 if( opt_name == help_opt ) {
00189 if(errout) printHelpMessage( argv[0], *errout );
00190 return PARSE_HELP_PRINTED;
00191 }
00192 if( opt_name == pause_opt ) {
00193 if(procRank == 0) {
00194 std::cerr << "\nType 0 and press enter to continue : ";
00195 int dummy_int = 0;
00196 std::cin >> dummy_int;
00197 }
00198 #ifdef HAVE_MPI
00199 MPI_Barrier(MPI_COMM_WORLD);
00200 #endif
00201 continue;
00202 }
00203
00204 options_list_t::iterator itr = options_list_.find(opt_name);
00205 if( itr == options_list_.end() ) {
00206 if(procRank == 0)
00207 print_bad_opt(i,argv,errout);
00208 if( recogniseAllOptions() )
00209 return PARSE_UNRECOGNIZED_OPTION;
00210 else
00211 continue;
00212 }
00213
00214
00215 opt_val_val_t &opt_val_val = (*itr).second;
00216 opt_val_val.was_read = true;
00217 switch( opt_val_val.opt_type ) {
00218 case OPT_BOOL_TRUE:
00219 *(any_cast<bool*>(opt_val_val.opt_val)) = true;
00220 break;
00221 case OPT_BOOL_FALSE:
00222 *(any_cast<bool*>(opt_val_val.opt_val)) = false;
00223 break;
00224 case OPT_INT:
00225 *(any_cast<int*>(opt_val_val.opt_val)) = ::atoi(opt_val_str.c_str());
00226 break;
00227 case OPT_DOUBLE:
00228 *(any_cast<double*>(opt_val_val.opt_val)) = ::atof(opt_val_str.c_str());
00229 break;
00230 case OPT_STRING:
00231 *(any_cast<std::string*>(opt_val_val.opt_val)) = remove_quotes(opt_val_str);
00232 break;
00233 case OPT_ENUM_INT:
00234 if( !set_enum_value( i, argv, opt_name, any_cast<int>(opt_val_val.opt_val), remove_quotes(opt_val_str), errout ) )
00235 return PARSE_UNRECOGNIZED_OPTION;
00236 break;
00237 default:
00238 TEST_FOR_EXCEPT(true);
00239 }
00240 }
00241
00242 for(
00243 options_list_t::const_iterator itr = options_list_.begin();
00244 itr != options_list_.end();
00245 ++itr
00246 )
00247 {
00248 const std::string &opt_val_name = (*itr).first;
00249 const opt_val_val_t &opt_val_val = (*itr).second;
00250 if( opt_val_val.required && !opt_val_val.was_read ) {
00251 TEST_FOR_EXCEPTION(
00252 true, std::logic_error
00253 ,"Error, the option --"<<opt_val_name<<" was required but was not set!"
00254 );
00255 }
00256 }
00257
00258 RefCountPtr<FancyOStream>
00259 defaultOut = VerboseObjectBase::getDefaultOStream();
00260 if( defaultOut.get() && addOutputSetupOptions_ ) {
00261 if( output_all_front_matter_ != output_all_front_matter_default_ )
00262 defaultOut->setShowAllFrontMatter(output_all_front_matter_);
00263 if( output_show_line_prefix_ != output_show_line_prefix_default_ )
00264 defaultOut->setShowLinePrefix(output_show_line_prefix_);
00265 if( output_show_tab_count_ != output_show_tab_count_default_ )
00266 defaultOut->setShowTabCount(output_show_tab_count_);
00267 if( output_show_proc_rank_ != output_show_proc_rank_default_ )
00268 defaultOut->setShowProcRank(output_show_proc_rank_);
00269 if( output_to_root_rank_only_ != output_to_root_rank_only_default_ )
00270 defaultOut->setOutputToRootOnly(output_to_root_rank_only_);
00271 }
00272 return PARSE_SUCCESSFUL;
00273 }
00274
00275 void CommandLineProcessor::printHelpMessage( const char program_name[], std::ostream &out ) const
00276 {
00277 add_extra_output_setup_options();
00278 int procRank = GlobalMPISession::getRank();
00279 if (procRank == 0) {
00280 using std::setw;
00281 using std::endl;
00282
00283 const int opt_type_w = 8;
00284 const char spc_chars[] = " ";
00285
00286
00287 int opt_name_w = 19;
00288 options_documentation_list_t::const_iterator itr;
00289 for( itr = options_documentation_list_.begin(); itr != options_documentation_list_.end(); ++itr ) {
00290 opt_name_w = my_max(opt_name_w,itr->opt_name.length());
00291 if( itr->opt_type )
00292 opt_name_w = my_max(opt_name_w,itr->opt_name_false.length());
00293 }
00294 opt_name_w += 2;
00295
00296
00297 out
00298 << "Usage: " << program_name << " [options]\n"
00299 << spc_chars << "options:\n"
00300 << spc_chars
00301 << "--"
00302 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00303 << std::left << setw(opt_name_w) << "help"
00304 << std::left << setw(opt_type_w) << " "
00305 #else
00306 << std::setiosflags(std::ios::left) << setw(opt_name_w) << "help"
00307 << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00308 #endif
00309 << "Prints this help message"
00310 << endl
00311 << spc_chars
00312 << "--"
00313 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00314 << std::left << setw(opt_name_w) << "pause-for-debugging"
00315 << std::left << setw(opt_type_w) << " "
00316 #else
00317 << std::setiosflags(std::ios::left) << setw(opt_name_w) << "pause-for-debugging"
00318 << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00319 #endif
00320 << "Pauses for user input to allow attaching a debugger"
00321 << endl
00322 << spc_chars
00323 << "--"
00324 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00325 << std::left << setw(opt_name_w) << "echo-command-line"
00326 << std::left << setw(opt_type_w) << " "
00327 #else
00328 << std::setiosflags(std::ios::left) << setw(opt_name_w) << "echo-command-line"
00329 << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00330 #endif
00331 << "Echo the command-line but continue as normal"
00332 << endl;
00333 for( itr = options_documentation_list_.begin(); itr != options_documentation_list_.end(); ++itr ) {
00334
00335 out
00336 << spc_chars
00337 << "--"
00338 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00339 << std::left << setw(opt_name_w) << itr->opt_name
00340 << std::left << setw(opt_type_w) << opt_type_str(itr->opt_type)
00341 #else
00342 << std::setiosflags(std::ios::left) << setw(opt_name_w) << itr->opt_name
00343 << std::setiosflags(std::ios::left) << setw(opt_type_w) << opt_type_str(itr->opt_type)
00344 #endif
00345 << ( itr->documentation.length() ? itr->documentation.c_str() : "No documentation" )
00346 << endl;
00347
00348 if( itr->opt_type == OPT_ENUM_INT ) {
00349 out
00350 << spc_chars
00351 << " "
00352 << setw(opt_name_w) << ""
00353 << setw(opt_type_w) << "";
00354 print_enum_opt_names( any_cast<int>(itr->default_val), out );
00355 out
00356 << endl;
00357 }
00358
00359 if( itr->opt_type == OPT_BOOL_TRUE ) {
00360 out
00361 << spc_chars
00362 << "--"
00363 << setw(opt_name_w) << itr->opt_name_false;
00364 }
00365 else {
00366 out
00367 << spc_chars
00368 << " "
00369 << setw(opt_name_w) << " ";
00370 }
00371 out
00372 << setw(opt_type_w) << " "
00373 << "(default: ";
00374 switch( itr->opt_type ) {
00375 case OPT_BOOL_TRUE:
00376 out << "--" << ( (*(any_cast<bool*>(itr->default_val))) ? itr->opt_name : itr->opt_name_false );
00377 break;
00378 case OPT_INT:
00379 case OPT_DOUBLE:
00380 case OPT_STRING:
00381 case OPT_ENUM_INT:
00382 out << "--" << itr->opt_name;
00383 break;
00384 default:
00385 TEST_FOR_EXCEPT(true);
00386 }
00387 switch( itr->opt_type ) {
00388 case OPT_BOOL_TRUE:
00389 break;
00390 case OPT_INT:
00391 out << "=" << (*(any_cast<int*>(itr->default_val)));
00392 break;
00393 case OPT_DOUBLE:
00394 out << "=" << (*(any_cast<double*>(itr->default_val)));
00395 break;
00396 case OPT_STRING:
00397 out << "=" << add_quotes(*(any_cast<std::string*>(itr->default_val)));
00398 break;
00399 case OPT_ENUM_INT:
00400 out << "=" << add_quotes(enum_opt_default_val_name(itr->opt_name,any_cast<int>(itr->default_val),&out));
00401 break;
00402 default:
00403 TEST_FOR_EXCEPT(true);
00404 }
00405 out << ")\n";
00406 }
00407 if(doc_string_.length()) {
00408 out << "\nDETAILED DOCUMENTATION:\n\n" << doc_string_ << endl << endl;
00409 }
00410 if(throwExceptions_)
00411 TEST_FOR_EXCEPTION( true, HelpPrinted, "Help message was printed" );
00412 }
00413 }
00414
00415
00416
00417 void CommandLineProcessor::add_extra_output_setup_options() const
00418 {
00419 if(
00420 in_add_extra_output_setup_options_
00421 ||
00422 added_extra_output_setup_options_
00423 ||
00424 !addOutputSetupOptions_
00425 )
00426 {
00427 return;
00428 }
00429
00430 CommandLineProcessor
00431 *clp = const_cast<CommandLineProcessor*>(this);
00432 clp->in_add_extra_output_setup_options_ = true;
00433 clp->setOption(
00434 "output-all-front-matter","output-no-front-matter",&clp->output_all_front_matter_
00435 ,"Set if all front matter is printed to the default FancyOStream or not"
00436 );
00437 clp->setOption(
00438 "output-show-line-prefix","output-no-show-line-prefix",&clp->output_show_line_prefix_
00439 ,"Set if the line prefix matter is printed to the default FancyOStream or not"
00440 );
00441 clp->setOption(
00442 "output-show-tab-count","output-no-show-tab-count",&clp->output_show_tab_count_
00443 ,"Set if the tab count is printed to the default FancyOStream or not"
00444 );
00445 clp->setOption(
00446 "output-show-proc-rank","output-no-show-proc-rank",&clp->output_show_proc_rank_
00447 ,"Set if the processor rank is printed to the default FancyOStream or not"
00448 );
00449 clp->setOption(
00450 "output-to-root-rank-only",&clp->output_to_root_rank_only_
00451 ,"Set which processor (the root) gets the output. If < 0, then all processors get output."
00452 );
00453 clp->added_extra_output_setup_options_ = true;
00454 clp->in_add_extra_output_setup_options_ = false;
00455 }
00456
00457 void CommandLineProcessor::setEnumOption(
00458 const char enum_option_name[]
00459 ,int *enum_option_val
00460 ,const int num_enum_opt_values
00461 ,const int enum_opt_values[]
00462 ,const char* enum_opt_names[]
00463 ,const char documentation[]
00464 ,const bool required
00465 )
00466 {
00467 add_extra_output_setup_options();
00468
00469 TEST_FOR_EXCEPT(enum_option_val==NULL);
00470 TEST_FOR_EXCEPT(num_enum_opt_values<=0);
00471 TEST_FOR_EXCEPT(enum_opt_values==NULL);
00472 TEST_FOR_EXCEPT(enum_opt_names==NULL);
00473
00474 enum_opt_data_list_.push_back(
00475 enum_opt_data_t(enum_option_val,num_enum_opt_values,enum_opt_values,enum_opt_names)
00476 );
00477 const int opt_id = enum_opt_data_list_.size()-1;
00478 options_list_[std::string(enum_option_name)]
00479 = opt_val_val_t(OPT_ENUM_INT,any(opt_id),required);
00480 options_documentation_list_.push_back(
00481 opt_doc_t(OPT_ENUM_INT,enum_option_name,"",std::string(documentation?documentation:""),any(opt_id))
00482 );
00483 }
00484
00485 bool CommandLineProcessor::set_enum_value(
00486 int argv_i
00487 ,char* argv[]
00488 ,const std::string &enum_opt_name
00489 ,const int enum_id
00490 ,const std::string &enum_str_val
00491 ,std::ostream *errout
00492 ) const
00493 {
00494 const enum_opt_data_t
00495 &enum_opt_data = enum_opt_data_list_.at(enum_id);
00496 std::vector<std::string>::const_iterator
00497 itr_begin = enum_opt_data.enum_opt_names.begin(),
00498 itr_end = enum_opt_data.enum_opt_names.end(),
00499 itr = std::find( itr_begin, itr_end, enum_str_val );
00500 if( itr == itr_end ) {
00501 const int j = argv_i;
00502 #define CLP_ERR_MSG \
00503 "Error, the value \"" << enum_str_val << "\" for the " \
00504 << j<<(j==1?"st":(j==2?"nd":(j==3?"rd":"th"))) << " option --" \
00505 << enum_opt_name << " was not recognized (use --help)!"
00506 if(errout)
00507 *errout << std::endl << argv[0] << " : " << CLP_ERR_MSG << std::endl;
00508 if( throwExceptions() ) {
00509 TEST_FOR_EXCEPTION( true, std::invalid_argument, CLP_ERR_MSG );
00510 }
00511 else {
00512 return false;
00513 }
00514 #undef CLP_ERR_MSG
00515 }
00516 const int enum_opt_val_index = itr - itr_begin;
00517 *enum_opt_data.enum_option_val = enum_opt_data.enum_opt_values.at(enum_opt_val_index);
00518 return true;
00519 }
00520
00521 void CommandLineProcessor::print_enum_opt_names(
00522 const int enum_id
00523 ,std::ostream &out
00524 ) const
00525 {
00526 const enum_opt_data_t
00527 &enum_opt_data = enum_opt_data_list_.at(enum_id);
00528 typedef std::vector<string>::const_iterator itr_t;
00529 out << "Valid options:";
00530 for( itr_t itr = enum_opt_data.enum_opt_names.begin(); itr != enum_opt_data.enum_opt_names.end() ; ++itr ) {
00531 if( itr != enum_opt_data.enum_opt_names.begin() ) out << ",";
00532 out << " " << add_quotes(*itr);
00533 }
00534 }
00535
00536 std::string
00537 CommandLineProcessor::enum_opt_default_val_name(
00538 const std::string &enum_name
00539 ,const int enum_id
00540 ,std::ostream *errout
00541 ) const
00542 {
00543 const enum_opt_data_t
00544 &enum_opt_data = enum_opt_data_list_.at(enum_id);
00545 return enum_opt_data.enum_opt_names.at(
00546 find_enum_opt_index(
00547 enum_name,*enum_opt_data.enum_option_val,enum_opt_data,errout
00548 )
00549 );
00550 }
00551
00552 int CommandLineProcessor::find_enum_opt_index(
00553 const std::string &enum_opt_name
00554 ,const int opt_value
00555 ,const enum_opt_data_t &enum_data
00556 ,std::ostream *errout
00557 ) const
00558 {
00559 std::vector<int>::const_iterator
00560 itr_begin = enum_data.enum_opt_values.begin(),
00561 itr_end = enum_data.enum_opt_values.end(),
00562 itr = std::find( itr_begin, itr_end, opt_value );
00563 if( itr == itr_end ) {
00564 #define CLP_ERR_MSG \
00565 ( recogniseAllOptions() ? "Error" : "Warning" ) \
00566 << ", option --" << enum_opt_name << " was given an invalid " \
00567 "initial option value of " << opt_value << "!"
00568 if(errout)
00569 *errout << CLP_ERR_MSG << std::endl;
00570 if( throwExceptions() )
00571 TEST_FOR_EXCEPTION( true, std::invalid_argument, CLP_ERR_MSG );
00572 #undef CLP_ERR_MSG
00573 }
00574 return itr - itr_begin;
00575 }
00576
00577 bool CommandLineProcessor::get_opt_val(
00578 const char str[]
00579 ,std::string *opt_name
00580 ,std::string *opt_val_str
00581 ) const
00582 {
00583 const int len = strlen(str);
00584 if( len < 3 )
00585 return false;
00586 if( str[0] != '-' || str[1] != '-' )
00587 return false;
00588
00589 int equ_i;
00590 for( equ_i = 2; equ_i < len && str[equ_i] != '='; ++equ_i );
00591
00592 opt_name->assign( str + 2, equ_i-2 );
00593
00594 if( equ_i == len ) {
00595 *opt_val_str = "";
00596 }
00597 else {
00598 opt_val_str->assign( str + equ_i + 1, len - equ_i - 1 );
00599 }
00600 return true;
00601 }
00602
00603 void CommandLineProcessor::print_bad_opt(
00604 int argv_i
00605 ,char* argv[]
00606 ,std::ostream *errout
00607 ) const
00608 {
00609 const int j = argv_i;
00610 #define CLP_ERR_MSG \
00611 ( recogniseAllOptions() ? "Error" : "Warning" ) \
00612 << ", the " << j<<(j==1?"st":(j==2?"nd":(j==3?"rd":"th"))) \
00613 << " option \'" << argv[argv_i] << "\' was not recognized (use --help)!"
00614 if(errout)
00615 *errout << std::endl << argv[0] << " : " << CLP_ERR_MSG << std::endl;
00616 if( recogniseAllOptions() && throwExceptions() )
00617 TEST_FOR_EXCEPTION( true, UnrecognizedOption, CLP_ERR_MSG );
00618 #undef CLP_ERR_MSG
00619 }
00620
00621 }
00622
00623