00001 #include "OBTOptionArgHandler.h"
00002 #include "OBTOptionArg.h"
00003 #include "OBTArgException.h"
00004 #include "OBT_ASSERT.h"
00005 #include <iostream>
00006 #include <sstream>
00007 #include <fstream>
00008
00009 namespace OBT
00010 {
00011
00012 class ArgsOp
00013 {
00014 public:
00015 ListArg _optionsList ;
00016 virtual ~ArgsOp() {}
00017 void usage() const ;
00018 virtual void testValidity() const ;
00019 virtual std::string msg() const = 0 ;
00020 virtual void throwErrorMsg() const ;
00021 virtual bool test( int nb ) const = 0 ;
00022 } ;
00023
00024 void ArgsOp::usage() const
00025 {
00026 std::cerr << msg() ;
00027 for( ListArg::const_iterator option = _optionsList.begin() ;
00028 option != _optionsList.end() ;
00029 option++ )
00030 {
00031 std::cerr << ( *option )->getName() << " " ;
00032 }
00033 std::cerr << std::endl ;
00034 }
00035
00036 void ArgsOp::throwErrorMsg() const
00037 {
00038 std::stringstream error ;
00039 error << std::endl << msg() << std::endl ;
00040 for( ListArg::const_iterator option = _optionsList.begin() ;
00041 option != _optionsList.end() ;
00042 option++ )
00043 {
00044 error << ( *option )->getHelp() << std::endl ;
00045 }
00046 throw ArgException( error.str() ) ;
00047 }
00048
00049 void ArgsOp::testValidity() const
00050 {
00051 int nb = 0 ;
00052 for( ListArg::const_iterator option = _optionsList.begin() ;
00053 option != _optionsList.end() ;
00054 option++ )
00055 {
00056 nb += ( *option )->nbPresent() ;
00057 }
00058 if( test( nb ) ) throwErrorMsg() ;
00059 }
00060
00061 class Imply : public ArgsOp
00062 {
00063 virtual std::string msg() const { return "The next option cannot be used if the previous one is not present: " ; }
00064 virtual bool test( int nb ) const { return true ; }
00065 virtual void testValidity() const
00066 {
00067 bool ok = true ;
00068 bool mustBePresent = ( *_optionsList.begin() )->isPresent() ;
00069 for( ListArg::const_iterator option = _optionsList.begin() ;
00070 option != _optionsList.end() && ok ;
00071 option++ )
00072 {
00073 ok = ok && mustBePresent == ( *option )->isPresent() ;
00074 mustBePresent = ( *option )->isPresent() ;
00075 }
00076 if( !ok ) throwErrorMsg() ;
00077 }
00078 } ;
00079
00080 class Exclusive : public ArgsOp
00081 {
00082 virtual std::string msg() const { return "The following options cannot be used together: " ; }
00083 virtual bool test( int nb ) const { return 1 < nb ; }
00084 } ;
00085
00086 class Inclusive : public ArgsOp
00087 {
00088 virtual std::string msg() const { return "The following options must be used together: " ; }
00089 virtual bool test( int nb ) const { return (int)_optionsList.size() == nb && 0 != nb ; }
00090 } ;
00091
00092 class AtLeastOne : public ArgsOp
00093 {
00094 virtual std::string msg() const { return "At least one of the following options must be used: " ; }
00095 virtual bool test( int nb ) const { return 0 == nb ; }
00096 } ;
00097
00098 OptionArgHandler& operator < ( OptionArg& o1, OptionArg& o2 )
00099 {
00100 OptionArgHandler::get().addOp( new Imply ) ;
00101 OptionArgHandler::get().addOp( o1 ) ;
00102 OptionArgHandler::get().addOp( o2 ) ;
00103 return OptionArgHandler::get() ;
00104 }
00105
00106 OptionArgHandler& operator < ( OptionArgHandler& h, OptionArg& o )
00107 {
00108 h.addOp( o ) ;
00109 return h ;
00110 }
00111
00112 OptionArgHandler& operator ^ ( OptionArg& o1, OptionArg& o2 )
00113 {
00114 OptionArgHandler::get().addOp( new Exclusive ) ;
00115 OptionArgHandler::get().addOp( o1 ) ;
00116 OptionArgHandler::get().addOp( o2 ) ;
00117 return OptionArgHandler::get() ;
00118 }
00119
00120 OptionArgHandler& operator ^ ( OptionArgHandler& h, OptionArg& o )
00121 {
00122 h.addOp( o ) ;
00123 return h ;
00124 }
00125
00126 OptionArgHandler& operator & ( OptionArg& o1, OptionArg& o2 )
00127 {
00128 OptionArgHandler::get().addOp( new Inclusive ) ;
00129 OptionArgHandler::get().addOp( o1 ) ;
00130 OptionArgHandler::get().addOp( o2 ) ;
00131 return OptionArgHandler::get() ;
00132 }
00133
00134 OptionArgHandler& operator & ( OptionArgHandler& h, OptionArg& o )
00135 {
00136 h.addOp( o ) ;
00137 return h ;
00138 }
00139
00140 OptionArgHandler& operator | ( OptionArg& o1, OptionArg& o2 )
00141 {
00142 OptionArgHandler::get().addOp( new AtLeastOne ) ;
00143 OptionArgHandler::get().addOp( o1 ) ;
00144 OptionArgHandler::get().addOp( o2 ) ;
00145 return OptionArgHandler::get() ;
00146 }
00147
00148 OptionArgHandler& operator | ( OptionArgHandler& h, OptionArg& o )
00149 {
00150 h.addOp( o ) ;
00151 return h ;
00152 }
00153
00154 }
00155
00156 using namespace OBT ;
00157
00158 void OptionArgHandler::addOp( ArgsOp* op )
00159 {
00160 _argOpList.push_back( op ) ;
00161 }
00162 void OptionArgHandler::addOp( OptionArg& o )
00163 {
00164 _argOpList.back()->_optionsList.push_back( &o ) ;
00165 }
00166
00167 OptionArgHandler* OptionArgHandler::_currentHandler = 0 ;
00168
00169 OptionArgHandler& OptionArgHandler::get()
00170 {
00171 OBT_ASSERT( 0 != _currentHandler && "not initialised" ) ;
00172 return *_currentHandler ;
00173 }
00174
00175 OptionArgHandler::OptionArgHandler()
00176 : _args(),
00177 _argIterator( 0 ),
00178 _optionList()
00179 {
00180 _currentHandler = this ;
00181 }
00182
00183 OptionArgHandler::~OptionArgHandler()
00184 {
00185 _currentHandler = 0 ;
00186 for( ListArg::iterator i = _optionList.begin() ; i != _optionList.end() ; ++i )
00187 {
00188 (*i)->_handler = 0 ;
00189 }
00190 }
00191
00192 void OptionArgHandler::reset()
00193 {
00194 _args.clear() ;
00195 _argIterator = 0 ;
00196 for( ListArg::iterator i = _optionList.begin() ; i != _optionList.end() ; ++i )
00197 {
00198 (*i)->reset() ;
00199 }
00200 }
00201
00202 void OptionArgHandler::usage() const
00203 {
00204 std::cerr << "options:" << std::endl ;
00205 for( ListArg::const_iterator option = _optionList.begin() ;
00206 option != _optionList.end() ;
00207 option++ )
00208 {
00209 std::cerr << ( *option )->getHelp() << std::endl ;
00210 }
00211 std::cerr << std::endl ;
00212
00213 for( ArgsOpList::const_iterator op = _argOpList.begin() ;
00214 op != _argOpList.end() ;
00215 op++ )
00216 {
00217 ( *op )->usage() ;
00218 }
00219 std::cerr << std::endl ;
00220 }
00221
00222 int OptionArgHandler::parseFile( const char* file, bool showUsageAndExit )
00223 {
00224 std::string args ;
00225 try
00226 {
00227 std::ifstream cfg( file );
00228 if( !cfg.is_open() )
00229 {
00230 std::stringstream error ;
00231 error << std::endl << "Unable to open the file \"" << file << "\"" << std::endl ;
00232 throw ArgException( error.str() ) ;
00233 }
00234 std::getline( cfg, args ) ;
00235 if( !cfg.good() )
00236 {
00237 std::stringstream error ;
00238 error << std::endl << "Unable to read the file \"" << file << "\"" << std::endl ;
00239 throw ArgException( error.str() ) ;
00240 }
00241 }
00242 catch( ArgException& error )
00243 {
00244 if( showUsageAndExit )
00245 {
00246 std::cerr << error.what() ;
00247 showUsage() ;
00248 }
00249 }
00250 return parse( args, showUsageAndExit, 0 ) ;
00251 }
00252
00253 int OptionArgHandler::parse( int argc, char* argv[], bool showUsageAndExit, int firstArg )
00254 {
00255 std::vector< std::string > args ;
00256 for( int i = 0 ; i < argc ; i++ )
00257 {
00258 args.push_back( std::string( argv[ i ] ) ) ;
00259 }
00260 return parse( args, showUsageAndExit, firstArg ) ;
00261 }
00262
00263 int OptionArgHandler::parse( const std::string& argss, bool showUsageAndExit, int firstArg )
00264 {
00265 std::vector< std::string > args ;
00266 std::size_t length = argss.length() ;
00267 for( std::size_t posB = 0 ; posB < length ; )
00268 {
00269 bool quotedArg = ( argss[ posB ] == '"' ) ;
00270 posB += quotedArg ? 1 : 0 ;
00271
00272 std::size_t posE = argss.find( quotedArg ? '"' : ' ', posB ) ;
00273 if( std::string::npos == posE )
00274 {
00275 args.push_back( argss.substr( posB ) ) ;
00276 break ;
00277 }
00278 std::string arg( argss.substr( posB, posE - posB ) ) ;
00279 if( !arg.empty() || quotedArg ) args.push_back( arg ) ;
00280 posB = ( quotedArg ? 1 : 0 ) + posE + 1 ;
00281 }
00282 return parse( args, showUsageAndExit, firstArg ) ;
00283 }
00284
00285 int OptionArgHandler::parse( const std::vector< std::string >& args, bool showUsageAndExit, int firstArg )
00286 {
00287 _args = args ;
00288 int nbOptions = 0 ;
00289 try
00290 {
00291 for( _argIterator = firstArg ; _argIterator < _args.size() ; )
00292 {
00293 bool flagFound = false ;
00294 for( ListArg::iterator option = _optionList.begin() ;
00295 option != _optionList.end() && !flagFound ;
00296 option++ )
00297 {
00298 flagFound = ( *option )->tryArg() ;
00299 }
00300 if( flagFound )
00301 {
00302 nbOptions++ ;
00303 }
00304 else
00305 {
00306 std::stringstream error ;
00307 error << std::endl << "Unable to parse argument #" << _argIterator
00308 << ": unknow option \"" << _args[ _argIterator ] << "\"" << std::endl ;
00309 throw ArgException( error.str() ) ;
00310 }
00311 }
00312
00313 for( ArgsOpList::const_iterator op = _argOpList.begin() ;
00314 op != _argOpList.end() ;
00315 op++ )
00316 {
00317 ( *op )->testValidity() ;
00318 }
00319 }
00320 catch( ArgException& error )
00321 {
00322 if( showUsageAndExit )
00323 {
00324 std::cerr << error.what() ;
00325 showUsage() ;
00326 }
00327 }
00328 return nbOptions ;
00329 }
00330