MOAB: Mesh Oriented datABase  (version 5.2.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) kraftche@cae.wisc.edu
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 <stdlib.h>
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() ) { stream << "[-" << mFlags[i]->flag() << ' ' << str << "]"; }
00151         else
00152         {
00153             str = mFlags[i]->brief();
00154             if( !str.empty() ) stream << " [" << str << "]";
00155         }
00156     }
00157     print_arg_names( stream );
00158     stream << std::endl;
00159     stream << progName << " -" << HELP_FLAG << std::endl;
00160     stream << progName << " -" << MAN_FLAG << std::endl;
00161 }
00162 
00163 void CLArgImpl::print_man( std::ostream& stream )
00164 {
00165     ManPage::begin_manpage( stream, progName, 1 );
00166 
00167     ManPage::begin_section( stream, "NAME" );
00168     ManPage::begin_paragraph( stream );
00169     stream << progName << " - " << shortDesc << std::endl << std::endl;
00170 
00171     ManPage::begin_section( stream, "SYNOPSIS" );
00172     ManPage::begin_hanging_paragraph( stream );
00173     ManPage::bold( stream, progName );
00174     for( unsigned i = 0; i < mFlags.size(); ++i )
00175     {
00176         std::string s = mFlags[i]->callback()->manstr();
00177         if( !s.empty() )
00178         {
00179             stream << '[';
00180             ManPage::begin_bold( stream );
00181             stream << '-' << mFlags[i]->flag();
00182             ManPage::end_bold( stream );
00183             stream << s << ']';
00184         }
00185         else
00186         {
00187             s = mFlags[i]->manstr();
00188             if( !s.empty() ) stream << " [" << s << "]";
00189         }
00190     }
00191     print_arg_names( stream );
00192     stream << std::endl;
00193     ManPage::begin_hanging_paragraph( stream );
00194     ManPage::bold( stream, progName + " -h" );
00195     ManPage::begin_hanging_paragraph( stream );
00196     ManPage::bold( stream, progName + " -M" );
00197 
00198     ManPage::begin_section( stream, "DESCRIPTION" );
00199     ManPage::write_text( stream, false, longDesc );
00200 
00201     ManPage::begin_section( stream, "OPTIONS" );
00202     for( unsigned i = 0; i < mFlags.size(); ++i )
00203     {
00204         std::string s = mFlags[i]->callback()->manstr();
00205         if( !s.empty() )
00206         {
00207             char tmp[] = { '-', mFlags[i]->flag(), ' ', '\0' };
00208             s          = std::string( tmp ) + s;
00209         }
00210         else
00211         {
00212             s = mFlags[i]->manstr();
00213             if( s.empty() ) continue;
00214         }
00215 
00216         ManPage::begin_hanging_paragraph( stream );
00217         stream << s;
00218         ManPage::begin_indent( stream );
00219         ManPage::begin_paragraph( stream );
00220         stream << mFlags[i]->desc();
00221         s = mFlags[i]->callback()->desc_append();
00222         if( !s.empty() ) stream << " " << s;
00223         std::string defval = mFlags[i]->callback()->default_str();
00224         if( !defval.empty() ) stream << " (default: " << defval << ")";
00225         ManPage::end_indent( stream );
00226     }
00227 }
00228 
00229 void CLArgImpl::print_arg_names( std::ostream& stream )
00230 {
00231     unsigned i;
00232     for( i = 0; i < reqArgNames.size(); ++i )
00233         stream << " <" << reqArgNames[i] << ">";
00234     for( i = 0; i < optArgNames.size(); ++i )
00235         stream << " [" << optArgNames[i] << "]";
00236 }
00237 
00238 CLArgs::CLArgs( const char* progname, const char* brief, const char* desc )
00239 {
00240     impl = new CLArgImpl( progname, brief, desc );
00241 }
00242 
00243 CLArgs::~CLArgs()
00244 {
00245     delete impl;
00246 }
00247 
00248 bool CLArgs::is_flag_available( char fl ) const
00249 {
00250     return ( fl != HELP_FLAG ) && ( fl != MAN_FLAG ) && !( impl->find_flag( fl ) );
00251 }
00252 
00253 bool CLArgs::str_flag( char fl, const char* name, const char* desc, CLArgs::StringArgI* callback )
00254 {
00255     if( !is_flag_available( fl ) ) return false;
00256     return impl->add_flag( new CLArgString( fl, name, desc, callback ) );
00257 }
00258 
00259 bool CLArgs::int_flag( char fl, const char* name, const char* desc, CLArgs::IntArgI* callback )
00260 {
00261     if( !is_flag_available( fl ) ) return false;
00262     return impl->add_flag( new CLArgInt( fl, name, desc, callback ) );
00263 }
00264 
00265 bool CLArgs::long_flag( char fl, const char* name, const char* desc, CLArgs::LongArgI* callback )
00266 {
00267     if( !is_flag_available( fl ) ) return false;
00268     return impl->add_flag( new CLArgLong( fl, name, desc, callback ) );
00269 }
00270 
00271 bool CLArgs::double_flag( char fl, const char* name, const char* desc, CLArgs::DoubleArgI* callback )
00272 {
00273     if( !is_flag_available( fl ) ) return false;
00274     return impl->add_flag( new CLArgDouble( fl, name, desc, callback ) );
00275 }
00276 
00277 bool CLArgs::toggle_flag( char on_flag, char off_flag, const char* desc, CLArgs::ToggleArgI* callback )
00278 {
00279     if( !( is_flag_available( on_flag ) && is_flag_available( off_flag ) ) ) return false;
00280 
00281     CLArgToggle* t1 = new CLArgToggle( on_flag, desc, true, callback );
00282     impl->add_flag( t1 );
00283     impl->add_flag( new CLArgToggle( off_flag, desc, t1 ) );
00284     return true;
00285 }
00286 
00287 bool CLArgs::toggle_flag( char fl, const char* desc, CLArgs::ToggleArgI* callback )
00288 {
00289     if( !is_flag_available( fl ) ) return false;
00290     return impl->add_flag( new CLArgToggle( fl, desc, true, callback ) );
00291 }
00292 
00293 bool CLArgs::id_list_flag( char fl, const char* desc, CLArgs::IntListArgI* callback )
00294 {
00295     if( !is_flag_available( fl ) ) return false;
00296     return impl->add_flag( new CLArgIDList( fl, desc, callback ) );
00297 }
00298 
00299 bool CLArgs::int_list_flag( char fl, const char* desc, CLArgs::IntListArgI* callback )
00300 {
00301     if( !is_flag_available( fl ) ) return false;
00302     return impl->add_flag( new CLArgIntList( fl, desc, callback ) );
00303 }
00304 
00305 bool CLArgs::double_list_flag( char fl, const char* desc, CLArgs::DoubleListArgI* callback )
00306 {
00307     if( !is_flag_available( fl ) ) return false;
00308     return impl->add_flag( new CLArgDoubleList( fl, desc, callback ) );
00309 }
00310 
00311 bool CLArgs::limit_list_flag( char fl, int num_values, const char* const* value_names )
00312 {
00313     CLArgFlag* f = impl->find_flag( fl );
00314     return f ? f->add_set( num_values, value_names ) : false;
00315 }
00316 
00317 void CLArgs::add_required_arg( const char* name )
00318 {
00319     impl->add_req_arg( name );
00320 }
00321 
00322 void CLArgs::add_optional_arg( const char* name )
00323 {
00324     impl->add_opt_arg( name );
00325 }
00326 
00327 bool CLArgs::parse_options( int argc, char** argv, std::vector< std::string >& args_out, std::ostream& error_stream )
00328 {
00329     std::vector< CLArgFlag* > pending;
00330     bool no_more_flags = false;
00331     for( int i = 1; i < argc; ++i )
00332     {
00333         if( !pending.empty() )
00334         {
00335             CLArgFlag* flag = pending.front();
00336             pending.erase( pending.begin() );
00337             if( !flag->parse( argv[i] ) )
00338             {
00339                 error_stream << argv[0] << ": invalid value for flag: -" << flag->flag() << " \"" << argv[i] << '"'
00340                              << std::endl;
00341                 return false;
00342             }
00343         }
00344         else if( !no_more_flags && argv[i][0] == '-' && argv[i][1] != '\0' )
00345         {
00346             for( int j = 1; argv[i][j]; ++j )
00347             {
00348                 if( argv[i][j] == HELP_FLAG )
00349                 {
00350                     print_help( std::cout );
00351                     exit( 0 );
00352                 }
00353                 else if( argv[i][j] == MAN_FLAG )
00354                 {
00355                     print_man_page( std::cout );
00356                     exit( 0 );
00357                 }
00358 
00359                 CLArgFlag* flag = impl->find_flag( argv[i][j] );
00360                 if( !flag )
00361                 {
00362                     error_stream << argv[0] << ": invalid flag: -" << argv[i][j] << std::endl;
00363                     return false;
00364                 }
00365                 else if( !flag->is_toggle() )
00366                 {
00367                     pending.push_back( flag );
00368                 }
00369                 else if( !flag->parse( NULL ) )
00370                 {
00371                     error_stream << argv[0] << ": conflicting flag: -" << argv[i][j] << std::endl;
00372                     return false;
00373                 }
00374             }
00375         }
00376         else if( !impl->add_parsed_arg( argv[i] ) )
00377         {
00378             error_stream << argv[0] << ": unexpected argument: \"" << argv[i] << '"' << std::endl;
00379             return false;
00380         }
00381     }
00382 
00383     impl->get_args( args_out );
00384 
00385     if( !pending.empty() )
00386     {
00387         error_stream << argv[0] << ": expected argument following flag: -" << pending.front()->flag() << std::endl;
00388         return false;
00389     }
00390     if( !impl->have_required_args() )
00391     {
00392         error_stream << argv[0] << ": insufficient arguments" << std::endl;
00393         return false;
00394     }
00395 
00396     return true;
00397 }
00398 
00399 void CLArgs::print_help( std::ostream& stream ) const
00400 {
00401     impl->print_help( stream );
00402 }
00403 
00404 void CLArgs::print_man_page( std::ostream& stream ) const
00405 {
00406     impl->print_man( stream );
00407 }
00408 
00409 void CLArgs::print_usage( std::ostream& stream ) const
00410 {
00411     impl->print_brief_help( stream );
00412 }
00413 
00414 void CLArgs::KeyWordArg::initialize( const char* keyword_list[], int list_length )
00415 {
00416     mKeyWords.resize( list_length );
00417     std::copy( keyword_list, keyword_list + list_length, mKeyWords.begin() );
00418 }
00419 
00420 bool CLArgs::KeyWordArg::value( const std::string& val )
00421 {
00422     std::vector< std::string >::const_iterator i;
00423     for( i = mKeyWords.begin(); i != mKeyWords.end(); ++i )
00424         if( compare_no_case( i->c_str(), val.c_str() ) ) { return value( *i ); }
00425 
00426     return false;
00427 }
00428 
00429 std::string CLArgs::KeyWordArg::brief() const
00430 {
00431     std::ostringstream ss;
00432     std::vector< std::string >::const_iterator i = mKeyWords.begin();
00433     if( i == mKeyWords.end() ) return std::string();
00434 
00435     ss << '{' << *i;
00436     for( ++i; i != mKeyWords.end(); ++i )
00437         ss << '|' << *i;
00438     ss << '}';
00439     return ss.str();
00440 }
00441 
00442 std::string CLArgs::KeyWordArg::manstr() const
00443 {
00444     if( mKeyWords.empty() ) return std::string();
00445 
00446     std::ostringstream ss;
00447     ManPage::bold( ss, mKeyWords[0].c_str() );
00448     for( unsigned i = 1; i < mKeyWords.size(); ++i )
00449     {
00450         ss << "|";
00451         ManPage::bold( ss, mKeyWords[i].c_str() );
00452     }
00453     return ss.str();
00454 }
00455 
00456 bool CLArgs::KeyWordArg::compare_no_case( const char* s1, const char* s2 )
00457 {
00458     for( ; *s1; ++s1, ++s2 )
00459         if( toupper( *s1 ) != toupper( *s2 ) ) return false;
00460     return !*s2;
00461 }
00462 
00463 CLArgs::IntRange::IntRange( const int* min, const int* max )
00464     : mMin( min ? *min : std::numeric_limits< int >::min() ), mMax( max ? *max : std::numeric_limits< int >::max() )
00465 {
00466 }
00467 
00468 bool CLArgs::IntRange::is_valid( int val ) const
00469 {
00470     return val >= mMin && val <= mMax;
00471 }
00472 
00473 std::string CLArgs::IntRange::desc_append() const
00474 {
00475     std::ostringstream ss;
00476     ss << "[" << mMin << "," << mMax << "]";
00477     return ss.str();
00478 }
00479 
00480 bool CLArgs::IntRangeArg::value( const int& val )
00481 {
00482     if( !mRange.is_valid( val ) ) return false;
00483     return IntArg::value( val );
00484 }
00485 
00486 bool CLArgs::IntListRangeArg::value( const std::vector< int >& val )
00487 {
00488     for( std::vector< int >::const_iterator i = val.begin(); i != val.end(); ++i )
00489         if( !mRange.is_valid( *i ) ) return false;
00490     return IntListArg::value( val );
00491 }
00492 
00493 CLArgs::DoubleRange::DoubleRange( const double* min, const double* max, bool inclusive )
00494     : haveMin( min != NULL ), haveMax( max != NULL ), mInclusive( inclusive )
00495 {
00496     if( haveMin ) mMin = *min;
00497     if( haveMax ) mMax = *max;
00498 }
00499 
00500 bool CLArgs::DoubleRange::is_valid( double val ) const
00501 {
00502     if( mInclusive )
00503         return ( !haveMin || val >= mMin ) && ( !haveMax || val <= mMax );
00504     else
00505         return ( !haveMin || val > mMin ) && ( !haveMax || val < mMax );
00506 }
00507 
00508 std::string CLArgs::DoubleRange::desc_append() const
00509 {
00510     std::ostringstream ss;
00511     if( mInclusive && haveMin )
00512         ss << '[';
00513     else
00514         ss << '(';
00515     if( haveMin )
00516         ss << mMin;
00517     else
00518         ss << "-inf";
00519     ss << ",";
00520     if( haveMax )
00521         ss << mMax;
00522     else
00523         ss << "inf";
00524     if( mInclusive && haveMax )
00525         ss << ']';
00526     else
00527         ss << ')';
00528     return ss.str();
00529 }
00530 
00531 bool CLArgs::DoubleRangeArg::value( const double& val )
00532 {
00533     if( !mRange.is_valid( val ) ) return false;
00534     return DoubleArg::value( val );
00535 }
00536 
00537 bool CLArgs::DoubleListRangeArg::value( const std::vector< double >& val )
00538 {
00539     for( std::vector< double >::const_iterator i = val.begin(); i != val.end(); ++i )
00540         if( !mRange.is_valid( *i ) ) return false;
00541     return DoubleListArg::value( val );
00542 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines