Teuchos_CommandLineProcessor.cpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 // //////////////////////////////////////////////////
00030 // Teuchos_CommandLineProcessor.cpp
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 } // end namespace
00058 
00059 namespace Teuchos {
00060 
00061 CommandLineProcessor::CommandLineProcessor(
00062   bool   throwExceptions
00063   ,bool  recogniseAllOptions
00064   )
00065   :throwExceptions_(throwExceptions)
00066   ,recogniseAllOptions_(recogniseAllOptions)
00067 {}
00068 
00069 // Set up options
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   assert(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   assert(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   assert(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   assert(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 // Parse command line
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   MPI_Comm_rank( MPI_COMM_WORLD, &procRank );
00142 #endif
00143   for( int i = 1; i < argc; ++i ) {
00144     bool gov_return = get_opt_val( argv[i], &opt_name, &opt_val_str );
00145     if( !gov_return && 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     if( opt_name == help_opt ) {
00153 #ifdef HAVE_MPI
00154       if (procRank == 0)
00155 #endif
00156       print_help_msg( argc, argv, errout );
00157       return PARSE_HELP_PRINTED;
00158     }
00159     if( opt_name == pause_opt ) {
00160 #ifdef HAVE_MPI
00161       if(procRank == 0) {
00162 #endif
00163         std::cerr << "\nType 0 and press enter to continue : ";
00164         int dummy_int = 0;
00165         std::cin >> dummy_int;
00166 #ifdef HAVE_MPI
00167       }
00168       MPI_Barrier(MPI_COMM_WORLD);
00169 #endif
00170       continue;
00171     }
00172     // Lookup the option (we had better find it!)
00173     options_list_t::const_iterator  itr = options_list_.find(opt_name);
00174     if( itr == options_list_.end() && recogniseAllOptions() ) {
00175 #ifdef HAVE_MPI
00176       if(procRank == 0)
00177 #endif
00178       print_bad_opt(i,argv,errout);
00179       return PARSE_UNRECOGNIZED_OPTION;
00180     }
00181     // Changed access to second value of map to not use overloaded arrow operator, 
00182     // otherwise this code will not compile on Janus (HKT, 12/01/2003) 
00183     const opt_val_val_t &opt_val_val = (*itr).second;
00184     switch( opt_val_val.opt_type ) {
00185       case OPT_BOOL_TRUE:
00186         *((bool*)opt_val_val.opt_val) = true;
00187         break;
00188       case OPT_BOOL_FALSE:
00189         *((bool*)opt_val_val.opt_val) = false;
00190         break;
00191       case OPT_INT:
00192         *((int*)opt_val_val.opt_val) = ::atoi(opt_val_str.c_str());
00193         break;
00194       case OPT_DOUBLE:
00195         *((double*)opt_val_val.opt_val) = ::atof(opt_val_str.c_str());
00196         break;
00197       case OPT_STRING:
00198         *((std::string*)opt_val_val.opt_val) = remove_quotes(opt_val_str);
00199         break;
00200       default:
00201         assert(0); // Local programming error only
00202     } 
00203   }
00204   return PARSE_SUCCESSFUL;
00205 }
00206 
00207 // private
00208 
00209 bool CommandLineProcessor::get_opt_val(
00210   const char     str[]
00211   ,std::string   *opt_name
00212   ,std::string   *opt_val_str
00213   ) const
00214 {
00215   const int len = strlen(str);
00216   if( len < 3 )
00217     return false; // Can't be an option with '--' followed by at least one char
00218   if( str[0] != '-' || str[1] != '-' )
00219     return false; // Not a recognised option
00220   // Find the '='
00221   int equ_i;
00222   for( equ_i = 2; equ_i < len && str[equ_i] != '='; ++equ_i );
00223   // Set opt_name
00224   opt_name->assign( str + 2, equ_i-2 );
00225   // Set opt_val_str
00226   if( equ_i == len ) {
00227     *opt_val_str = "";
00228   }
00229   else {
00230     opt_val_str->assign( str + equ_i + 1, len - equ_i - 1 );
00231   }
00232   return true;
00233 }
00234 
00235 void CommandLineProcessor::print_help_msg(
00236   int             argc
00237   ,char*          argv[]
00238   ,std::ostream   *errout
00239   ) const
00240 {
00241   using std::setw;
00242   using std::endl;
00243 
00244   if( !errout )
00245     return;
00246 
00247   const int opt_type_w = 8;
00248   const char spc_chars[] = "  ";
00249 
00250   // Get the maximum length of an option name
00251   int opt_name_w = 19; // For the 'pause-for-debugging' option
00252   options_documentation_list_t::const_iterator itr;
00253   for( itr = options_documentation_list_.begin(); itr != options_documentation_list_.end(); ++itr ) {
00254     opt_name_w = my_max(opt_name_w,itr->opt_name.length());
00255     if( itr->opt_type )
00256       opt_name_w = my_max(opt_name_w,itr->opt_name_false.length());
00257   }
00258   opt_name_w += 2;
00259 
00260   // Print the help message
00261   *errout
00262     << "Usage: " << argv[0] << " [options]\n"
00263     << spc_chars << "options:\n"
00264     << spc_chars
00265     << "--"
00266 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00267     << std::left << setw(opt_name_w) << "help"
00268     << std::left << setw(opt_type_w) << " "
00269 #else
00270           << std::setiosflags(std::ios::left) << setw(opt_name_w) << "help"
00271           << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00272 #endif
00273     << "Prints this help message"
00274     << endl
00275     << spc_chars
00276     << "--"
00277 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00278     << std::left << setw(opt_name_w) << "pause-for-debugging"
00279     << std::left << setw(opt_type_w) << " "
00280 #else
00281           << std::setiosflags(std::ios::left) << setw(opt_name_w) << "pause-for-debugging"
00282           << std::setiosflags(std::ios::left) << setw(opt_type_w) << " "
00283 #endif
00284     << "Pauses for user input to allow attaching a debugger"
00285     << endl;
00286   for( itr = options_documentation_list_.begin(); itr != options_documentation_list_.end(); ++itr ) {
00287     *errout
00288       << spc_chars
00289       << "--"
00290 #ifdef HAVE_STD_IOS_BASE_FMTFLAGS
00291       << std::left << setw(opt_name_w) << itr->opt_name
00292       << std::left << setw(opt_type_w) << opt_type_str(itr->opt_type)
00293 #else
00294       << std::setiosflags(std::ios::left) << setw(opt_name_w) << itr->opt_name
00295       << std::setiosflags(std::ios::left) << setw(opt_type_w) << opt_type_str(itr->opt_type)
00296 #endif
00297       << ( itr->documentation.length() ? itr->documentation.c_str() : "No documentation" )
00298       << endl;
00299     if( itr->opt_type == OPT_BOOL_TRUE ) {
00300       *errout
00301         << spc_chars
00302         << "--"
00303         << setw(opt_name_w) << itr->opt_name_false;
00304     }
00305     else {
00306       *errout
00307         << spc_chars
00308         << "  "
00309         << setw(opt_name_w) << " ";
00310     }
00311     *errout
00312       << setw(opt_type_w) << " "
00313       << "(default: ";
00314     switch( itr->opt_type ) {
00315       case OPT_BOOL_TRUE:
00316         *errout << "--" << ( (*((bool*)itr->default_val)) ? itr->opt_name : itr->opt_name_false );
00317         break;
00318       case OPT_INT:
00319       case OPT_DOUBLE:
00320       case OPT_STRING:
00321         *errout << "--" << itr->opt_name;
00322         break;
00323       default:
00324         assert(0); // Local programming error only
00325     }   
00326     switch( itr->opt_type ) {
00327       case OPT_BOOL_TRUE:
00328         break;
00329       case OPT_INT:
00330         *errout << "=" << (*((int*)itr->default_val));
00331         break;
00332       case OPT_DOUBLE:
00333         *errout <<  "=" << (*((double*)itr->default_val));
00334         break;
00335       case OPT_STRING:
00336         *errout <<  "=" << add_quotes(*((std::string*)itr->default_val));
00337         break;
00338       default:
00339         assert(0); // Local programming error only
00340     }   
00341     *errout << ")\n";
00342   }
00343   if(throwExceptions_)
00344     TEST_FOR_EXCEPTION( true, HelpPrinted, "Help message was printed" );
00345 }
00346 
00347 void CommandLineProcessor::print_bad_opt(
00348   int             argv_i
00349   ,char*          argv[]
00350   ,std::ostream   *errout
00351   ) const
00352 {
00353 #   define CLP_ERR_MSG "Error, option " << argv_i-1 << " \'" << argv[argv_i] << "\' is not recognized (use --help)!"
00354   if(errout)
00355     *errout << argv[0] << " : " << CLP_ERR_MSG << std::endl;
00356   if(throwExceptions_)
00357     TEST_FOR_EXCEPTION( true, UnrecognizedOption, CLP_ERR_MSG );
00358 #   undef CLP_ERR_MSG
00359 }
00360 
00361 } // end namespace Teuchos
00362 
00363 

Generated on Thu Sep 18 12:42:50 2008 for Teuchos - Trilinos Tools Package by doxygen 1.3.9.1