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