MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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 }