MOAB: Mesh Oriented datABase  (version 5.4.1)
CLArgs.cpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2007 Sandia National Laboratories.  Developed at the
00005     University of Wisconsin--Madison under SNL contract number
00006     624796.  The U.S. Government and the University of Wisconsin
00007     retain certain rights to this software.
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2.1 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     (lgpl.txt) along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 
00023     (2008) [email protected]
00024 
00025   ***************************************************************** */
00026 
00027 /** \file CLArgs.cpp
00028  *  \brief
00029  *  \author Jason Kraftcheck
00030  */
00031 
00032 #include "Mesquite.hpp"
00033 #include "CLArgs.hpp"
00034 #include "CLArgFlag.hpp"
00035 #include "ManPage.hpp"
00036 #include <iostream>
00037 #include <sstream>
00038 #include <limits>
00039 #include <cstdlib>
00040 
00041 const char HELP_FLAG = 'h';
00042 const char MAN_FLAG  = 'M';
00043 
00044 class CLArgImpl
00045 {
00046   private:
00047     std::vector< CLArgFlag* > mFlags;
00048     std::vector< std::string > reqArgNames, optArgNames;
00049     std::vector< std::string > reqArg, optArg;
00050     std::string progName, shortDesc, longDesc;
00051 
00052   public:
00053     CLArgImpl( const char* progname, const char* brief, const char* desc )
00054         : progName( progname ), shortDesc( brief ), longDesc( desc )
00055     {
00056     }
00057 
00058     void add_req_arg( const char* name )
00059     {
00060         reqArgNames.push_back( name );
00061     }
00062 
00063     void add_opt_arg( const char* name )
00064     {
00065         optArgNames.push_back( name );
00066     }
00067 
00068     bool add_parsed_arg( const char* arg );
00069 
00070     bool add_flag( CLArgFlag* flag );
00071 
00072     CLArgFlag* find_flag( char flag );
00073     const CLArgFlag* find_flag( char flag ) const
00074     {
00075         return const_cast< CLArgImpl* >( this )->find_flag( flag );
00076     }
00077 
00078     bool have_required_args() const
00079     {
00080         return reqArgNames.size() == reqArg.size();
00081     }
00082 
00083     void get_args( std::vector< std::string >& result )
00084     {
00085         result = reqArg;
00086         result.resize( reqArg.size() + optArg.size() );
00087         std::copy( optArg.begin(), optArg.end(), result.begin() + reqArg.size() );
00088     }
00089 
00090     void print_help( std::ostream& stream );
00091     void print_brief_help( std::ostream& stream );
00092     void print_man( std::ostream& stream );
00093 
00094     void print_arg_names( std::ostream& stream );
00095 };
00096 
00097 bool CLArgImpl::add_flag( CLArgFlag* arg )
00098 {
00099     if( find_flag( arg->flag() ) ) return false;
00100 
00101     mFlags.push_back( arg );
00102     return true;
00103 }
00104 
00105 bool CLArgImpl::add_parsed_arg( const char* arg )
00106 {
00107     if( reqArg.size() < reqArgNames.size() )
00108         reqArg.push_back( arg );
00109     else if( optArg.size() < optArgNames.size() )
00110         optArg.push_back( arg );
00111     else
00112         return false;
00113 
00114     return true;
00115 }
00116 
00117 CLArgFlag* CLArgImpl::find_flag( char flag )
00118 {
00119     for( unsigned i = 0; i < mFlags.size(); ++i )
00120         if( mFlags[i]->flag() == flag ) return mFlags[i];
00121     return 0;
00122 }
00123 
00124 void CLArgImpl::print_help( std::ostream& stream )
00125 {
00126     stream << progName << " : " << shortDesc << std::endl;
00127     stream << std::endl << longDesc << std::endl << std::endl;
00128     print_brief_help( stream );
00129     stream << '-' << HELP_FLAG << " : Print this help text." << std::endl;
00130     stream << '-' << MAN_FLAG << " : Print man page text to standard output stream." << std::endl;
00131     stream << "--"
00132            << " : Treat all subsequent arguments as non-flag arguments." << std::endl;
00133     for( unsigned i = 0; i < mFlags.size(); ++i )
00134     {
00135         stream << '-' << mFlags[i]->flag() << " : " << mFlags[i]->desc();
00136         std::string extra = mFlags[i]->callback()->desc_append();
00137         if( !extra.empty() ) stream << " " << extra;
00138         std::string defval = mFlags[i]->callback()->default_str();
00139         if( !defval.empty() ) stream << " (default: " << defval << ")";
00140         stream << std::endl;
00141     }
00142 }
00143 
00144 void CLArgImpl::print_brief_help( std::ostream& stream )
00145 {
00146     stream << progName;
00147     for( unsigned i = 0; i < mFlags.size(); ++i )
00148     {
00149         std::string str = mFlags[i]->callback()->brief();
00150         if( !str.empty() )
00151         {
00152             stream << "[-" << mFlags[i]->flag() << ' ' << str << "]";
00153         }
00154         else
00155         {
00156             str = mFlags[i]->brief();
00157             if( !str.empty() ) stream << " [" << str << "]";
00158         }
00159     }
00160     print_arg_names( stream );
00161     stream << std::endl;
00162     stream << progName << " -" << HELP_FLAG << std::endl;
00163     stream << progName << " -" << MAN_FLAG << std::endl;
00164 }
00165 
00166 void CLArgImpl::print_man( std::ostream& stream )
00167 {
00168     ManPage::begin_manpage( stream, progName, 1 );
00169 
00170     ManPage::begin_section( stream, "NAME" );
00171     ManPage::begin_paragraph( stream );
00172     stream << progName << " - " << shortDesc << std::endl << std::endl;
00173 
00174     ManPage::begin_section( stream, "SYNOPSIS" );
00175     ManPage::begin_hanging_paragraph( stream );
00176     ManPage::bold( stream, progName );
00177     for( unsigned i = 0; i < mFlags.size(); ++i )
00178     {
00179         std::string s = mFlags[i]->callback()->manstr();
00180         if( !s.empty() )
00181         {
00182             stream << '[';
00183             ManPage::begin_bold( stream );
00184             stream << '-' << mFlags[i]->flag();
00185             ManPage::end_bold( stream );
00186             stream << s << ']';
00187         }
00188         else
00189         {
00190             s = mFlags[i]->manstr();
00191             if( !s.empty() ) stream << " [" << s << "]";
00192         }
00193     }
00194     print_arg_names( stream );
00195     stream << std::endl;
00196     ManPage::begin_hanging_paragraph( stream );
00197     ManPage::bold( stream, progName + " -h" );
00198     ManPage::begin_hanging_paragraph( stream );
00199     ManPage::bold( stream, progName + " -M" );
00200 
00201     ManPage::begin_section( stream, "DESCRIPTION" );
00202     ManPage::write_text( stream, false, longDesc );
00203 
00204     ManPage::begin_section( stream, "OPTIONS" );
00205     for( unsigned i = 0; i < mFlags.size(); ++i )
00206     {
00207         std::string s = mFlags[i]->callback()->manstr();
00208         if( !s.empty() )
00209         {
00210             char tmp[] = { '-', mFlags[i]->flag(), ' ', '\0' };
00211             s          = std::string( tmp ) + s;
00212         }
00213         else
00214         {
00215             s = mFlags[i]->manstr();
00216             if( s.empty() ) continue;
00217         }
00218 
00219         ManPage::begin_hanging_paragraph( stream );
00220         stream << s;
00221         ManPage::begin_indent( stream );
00222         ManPage::begin_paragraph( stream );
00223         stream << mFlags[i]->desc();
00224         s = mFlags[i]->callback()->desc_append();
00225         if( !s.empty() ) stream << " " << s;
00226         std::string defval = mFlags[i]->callback()->default_str();
00227         if( !defval.empty() ) stream << " (default: " << defval << ")";
00228         ManPage::end_indent( stream );
00229     }
00230 }
00231 
00232 void CLArgImpl::print_arg_names( std::ostream& stream )
00233 {
00234     unsigned i;
00235     for( i = 0; i < reqArgNames.size(); ++i )
00236         stream << " <" << reqArgNames[i] << ">";
00237     for( i = 0; i < optArgNames.size(); ++i )
00238         stream << " [" << optArgNames[i] << "]";
00239 }
00240 
00241 CLArgs::CLArgs( const char* progname, const char* brief, const char* desc )
00242 {
00243     impl = new CLArgImpl( progname, brief, desc );
00244 }
00245 
00246 CLArgs::~CLArgs()
00247 {
00248     delete impl;
00249 }
00250 
00251 bool CLArgs::is_flag_available( char fl ) const
00252 {
00253     return ( fl != HELP_FLAG ) && ( fl != MAN_FLAG ) && !( impl->find_flag( fl ) );
00254 }
00255 
00256 bool CLArgs::str_flag( char fl, const char* name, const char* desc, CLArgs::StringArgI* callback )
00257 {
00258     if( !is_flag_available( fl ) ) return false;
00259     return impl->add_flag( new CLArgString( fl, name, desc, callback ) );
00260 }
00261 
00262 bool CLArgs::int_flag( char fl, const char* name, const char* desc, CLArgs::IntArgI* callback )
00263 {
00264     if( !is_flag_available( fl ) ) return false;
00265     return impl->add_flag( new CLArgInt( fl, name, desc, callback ) );
00266 }
00267 
00268 bool CLArgs::long_flag( char fl, const char* name, const char* desc, CLArgs::LongArgI* callback )
00269 {
00270     if( !is_flag_available( fl ) ) return false;
00271     return impl->add_flag( new CLArgLong( fl, name, desc, callback ) );
00272 }
00273 
00274 bool CLArgs::double_flag( char fl, const char* name, const char* desc, CLArgs::DoubleArgI* callback )
00275 {
00276     if( !is_flag_available( fl ) ) return false;
00277     return impl->add_flag( new CLArgDouble( fl, name, desc, callback ) );
00278 }
00279 
00280 bool CLArgs::toggle_flag( char on_flag, char off_flag, const char* desc, CLArgs::ToggleArgI* callback )
00281 {
00282     if( !( is_flag_available( on_flag ) && is_flag_available( off_flag ) ) ) return false;
00283 
00284     CLArgToggle* t1 = new CLArgToggle( on_flag, desc, true, callback );
00285     impl->add_flag( t1 );
00286     impl->add_flag( new CLArgToggle( off_flag, desc, t1 ) );
00287     return true;
00288 }
00289 
00290 bool CLArgs::toggle_flag( char fl, const char* desc, CLArgs::ToggleArgI* callback )
00291 {
00292     if( !is_flag_available( fl ) ) return false;
00293     return impl->add_flag( new CLArgToggle( fl, desc, true, callback ) );
00294 }
00295 
00296 bool CLArgs::id_list_flag( char fl, const char* desc, CLArgs::IntListArgI* callback )
00297 {
00298     if( !is_flag_available( fl ) ) return false;
00299     return impl->add_flag( new CLArgIDList( fl, desc, callback ) );
00300 }
00301 
00302 bool CLArgs::int_list_flag( char fl, const char* desc, CLArgs::IntListArgI* callback )
00303 {
00304     if( !is_flag_available( fl ) ) return false;
00305     return impl->add_flag( new CLArgIntList( fl, desc, callback ) );
00306 }
00307 
00308 bool CLArgs::double_list_flag( char fl, const char* desc, CLArgs::DoubleListArgI* callback )
00309 {
00310     if( !is_flag_available( fl ) ) return false;
00311     return impl->add_flag( new CLArgDoubleList( fl, desc, callback ) );
00312 }
00313 
00314 bool CLArgs::limit_list_flag( char fl, int num_values, const char* const* value_names )
00315 {
00316     CLArgFlag* f = impl->find_flag( fl );
00317     return f ? f->add_set( num_values, value_names ) : false;
00318 }
00319 
00320 void CLArgs::add_required_arg( const char* name )
00321 {
00322     impl->add_req_arg( name );
00323 }
00324 
00325 void CLArgs::add_optional_arg( const char* name )
00326 {
00327     impl->add_opt_arg( name );
00328 }
00329 
00330 bool CLArgs::parse_options( int argc, char** argv, std::vector< std::string >& args_out, std::ostream& error_stream )
00331 {
00332     std::vector< CLArgFlag* > pending;
00333     bool no_more_flags = false;
00334     for( int i = 1; i < argc; ++i )
00335     {
00336         if( !pending.empty() )
00337         {
00338             CLArgFlag* flag = pending.front();
00339             pending.erase( pending.begin() );
00340             if( !flag->parse( argv[i] ) )
00341             {
00342                 error_stream << argv[0] << ": invalid value for flag: -" << flag->flag() << " \"" << argv[i] << '"'
00343                              << std::endl;
00344                 return false;
00345             }
00346         }
00347         else if( !no_more_flags && argv[i][0] == '-' && argv[i][1] != '\0' )
00348         {
00349             for( int j = 1; argv[i][j]; ++j )
00350             {
00351                 if( argv[i][j] == HELP_FLAG )
00352                 {
00353                     print_help( std::cout );
00354                     exit( 0 );
00355                 }
00356                 else if( argv[i][j] == MAN_FLAG )
00357                 {
00358                     print_man_page( std::cout );
00359                     exit( 0 );
00360                 }
00361 
00362                 CLArgFlag* flag = impl->find_flag( argv[i][j] );
00363                 if( !flag )
00364                 {
00365                     error_stream << argv[0] << ": invalid flag: -" << argv[i][j] << std::endl;
00366                     return false;
00367                 }
00368                 else if( !flag->is_toggle() )
00369                 {
00370                     pending.push_back( flag );
00371                 }
00372                 else if( !flag->parse( NULL ) )
00373                 {
00374                     error_stream << argv[0] << ": conflicting flag: -" << argv[i][j] << std::endl;
00375                     return false;
00376                 }
00377             }
00378         }
00379         else if( !impl->add_parsed_arg( argv[i] ) )
00380         {
00381             error_stream << argv[0] << ": unexpected argument: \"" << argv[i] << '"' << std::endl;
00382             return false;
00383         }
00384     }
00385 
00386     impl->get_args( args_out );
00387 
00388     if( !pending.empty() )
00389     {
00390         error_stream << argv[0] << ": expected argument following flag: -" << pending.front()->flag() << std::endl;
00391         return false;
00392     }
00393     if( !impl->have_required_args() )
00394     {
00395         error_stream << argv[0] << ": insufficient arguments" << std::endl;
00396         return false;
00397     }
00398 
00399     return true;
00400 }
00401 
00402 void CLArgs::print_help( std::ostream& stream ) const
00403 {
00404     impl->print_help( stream );
00405 }
00406 
00407 void CLArgs::print_man_page( std::ostream& stream ) const
00408 {
00409     impl->print_man( stream );
00410 }
00411 
00412 void CLArgs::print_usage( std::ostream& stream ) const
00413 {
00414     impl->print_brief_help( stream );
00415 }
00416 
00417 void CLArgs::KeyWordArg::initialize( const char* keyword_list[], int list_length )
00418 {
00419     mKeyWords.resize( list_length );
00420     std::copy( keyword_list, keyword_list + list_length, mKeyWords.begin() );
00421 }
00422 
00423 bool CLArgs::KeyWordArg::value( const std::string& val )
00424 {
00425     std::vector< std::string >::const_iterator i;
00426     for( i = mKeyWords.begin(); i != mKeyWords.end(); ++i )
00427         if( compare_no_case( i->c_str(), val.c_str() ) )
00428         {
00429             return value( *i );
00430         }
00431 
00432     return false;
00433 }
00434 
00435 std::string CLArgs::KeyWordArg::brief() const
00436 {
00437     std::ostringstream ss;
00438     std::vector< std::string >::const_iterator i = mKeyWords.begin();
00439     if( i == mKeyWords.end() ) return std::string();
00440 
00441     ss << '{' << *i;
00442     for( ++i; i != mKeyWords.end(); ++i )
00443         ss << '|' << *i;
00444     ss << '}';
00445     return ss.str();
00446 }
00447 
00448 std::string CLArgs::KeyWordArg::manstr() const
00449 {
00450     if( mKeyWords.empty() ) return std::string();
00451 
00452     std::ostringstream ss;
00453     ManPage::bold( ss, mKeyWords[0].c_str() );
00454     for( unsigned i = 1; i < mKeyWords.size(); ++i )
00455     {
00456         ss << "|";
00457         ManPage::bold( ss, mKeyWords[i].c_str() );
00458     }
00459     return ss.str();
00460 }
00461 
00462 bool CLArgs::KeyWordArg::compare_no_case( const char* s1, const char* s2 )
00463 {
00464     for( ; *s1; ++s1, ++s2 )
00465         if( toupper( *s1 ) != toupper( *s2 ) ) return false;
00466     return !*s2;
00467 }
00468 
00469 CLArgs::IntRange::IntRange( const int* min, const int* max )
00470     : mMin( min ? *min : std::numeric_limits< int >::min() ), mMax( max ? *max : std::numeric_limits< int >::max() )
00471 {
00472 }
00473 
00474 bool CLArgs::IntRange::is_valid( int val ) const
00475 {
00476     return val >= mMin && val <= mMax;
00477 }
00478 
00479 std::string CLArgs::IntRange::desc_append() const
00480 {
00481     std::ostringstream ss;
00482     ss << "[" << mMin << "," << mMax << "]";
00483     return ss.str();
00484 }
00485 
00486 bool CLArgs::IntRangeArg::value( const int& val )
00487 {
00488     if( !mRange.is_valid( val ) ) return false;
00489     return IntArg::value( val );
00490 }
00491 
00492 bool CLArgs::IntListRangeArg::value( const std::vector< int >& val )
00493 {
00494     for( std::vector< int >::const_iterator i = val.begin(); i != val.end(); ++i )
00495         if( !mRange.is_valid( *i ) ) return false;
00496     return IntListArg::value( val );
00497 }
00498 
00499 CLArgs::DoubleRange::DoubleRange( const double* min, const double* max, bool inclusive )
00500     : haveMin( min != NULL ), haveMax( max != NULL ), mInclusive( inclusive )
00501 {
00502     if( haveMin ) mMin = *min;
00503     if( haveMax ) mMax = *max;
00504 }
00505 
00506 bool CLArgs::DoubleRange::is_valid( double val ) const
00507 {
00508     if( mInclusive )
00509         return ( !haveMin || val >= mMin ) && ( !haveMax || val <= mMax );
00510     else
00511         return ( !haveMin || val > mMin ) && ( !haveMax || val < mMax );
00512 }
00513 
00514 std::string CLArgs::DoubleRange::desc_append() const
00515 {
00516     std::ostringstream ss;
00517     if( mInclusive && haveMin )
00518         ss << '[';
00519     else
00520         ss << '(';
00521     if( haveMin )
00522         ss << mMin;
00523     else
00524         ss << "-inf";
00525     ss << ",";
00526     if( haveMax )
00527         ss << mMax;
00528     else
00529         ss << "inf";
00530     if( mInclusive && haveMax )
00531         ss << ']';
00532     else
00533         ss << ')';
00534     return ss.str();
00535 }
00536 
00537 bool CLArgs::DoubleRangeArg::value( const double& val )
00538 {
00539     if( !mRange.is_valid( val ) ) return false;
00540     return DoubleArg::value( val );
00541 }
00542 
00543 bool CLArgs::DoubleListRangeArg::value( const std::vector< double >& val )
00544 {
00545     for( std::vector< double >::const_iterator i = val.begin(); i != val.end(); ++i )
00546         if( !mRange.is_valid( *i ) ) return false;
00547     return DoubleListArg::value( val );
00548 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines