00001
00002
00003
00004
00005
00006 #ifndef ANIMAL_command_line_parser________
00007 #define ANIMAL_command_line_parser________
00008
00009 #include <iostream>
00010 #include <stdlib.h>
00011
00012 #include <sstream>
00013 #include <fstream>
00014 #include <string>
00015 #include <vector>
00016 #include <algorithm>
00017 #include <map>
00018
00019 namespace animal {
00020
00021 typedef std::istringstream istrstream;
00022
00024 struct ArgumentBase
00025 {
00027 typedef std::string string;
00028
00035 ArgumentBase(char s, string l, string h, bool m)
00036 : shortName(s)
00037 , longName(l)
00038 , help(h)
00039 , mandatory(m)
00040 , isSet(false)
00041 {}
00042
00044 virtual ~ArgumentBase(){}
00045
00047 virtual bool read( std::istream& ) = 0;
00048
00050 virtual void printValue() const =0;
00051
00052 char shortName;
00053 string longName;
00054 string help;
00055
00057 inline void print () const
00058 {
00059 std::cout << "-" << shortName <<",\t--"<< longName <<":\t" << help;
00060 if( mandatory ) std::cout<< " (required) ";
00061 std::cout << " (default: "; printValue();
00062 std::cout << ")" << std::endl;
00063 }
00064
00066 bool mandatory;
00067
00069 bool isSet;
00070
00071
00072 };
00073
00074
00075
00076
00084 template < class T = void* >
00085 struct Argument : public ArgumentBase {
00086
00087
00095 Argument( T* t, char sn, string ln, string h, bool m )
00096 : ArgumentBase(sn,ln,h,m)
00097 , ptr(t)
00098 {}
00099
00100 inline void printValue() const ;
00101
00102 private:
00104 T* ptr;
00105
00106
00110 inline bool read( std::istream& str ){
00111 if( ! (str >> *ptr) ) return false;
00112 else {
00113 isSet = true;
00114 return true;
00115 }
00116 }
00117
00118 };
00119
00121 template<> inline
00122 bool Argument<bool>::read( std::istream& )
00123 {
00124 *ptr = true;
00125 isSet = true;
00126 return true;
00127 }
00128
00130 template<class T> inline
00131 void Argument<T>::printValue() const {
00132 std::cout << *ptr << " ";
00133 }
00134
00135
00136
00137
00138
00139
00140
00150 class ArgumentParser {
00152 typedef std::string string;
00154 typedef std::map< string, ArgumentBase* > Map;
00156 std::map< char, ArgumentBase* > shortName;
00158 Map longName;
00159
00161 typedef std::map<ArgumentBase*,bool> SetMap;
00162
00164 SetMap parameter_set;
00165
00167 typedef std::vector<ArgumentBase*> ArgVec;
00169 ArgVec commands;
00170
00171
00172 string globalHelp;
00173 char helpShortName;
00174 string helpLongName;
00175
00176 public:
00177
00179 ArgumentParser( const string& helpstr="", char hlpShrt='h', const string& hlpLng="help" )
00180 : globalHelp( helpstr )
00181 , helpShortName(hlpShrt)
00182 , helpLongName(hlpLng)
00183 {}
00184
00191 template<class T> inline
00192 ArgumentParser& option( T* ptr, char sho, char* lon, char* help )
00193 {
00194 string sn, ln(lon), h(help); sn += sho;
00195
00196 if( sho!=0 && shortName.find(sho) != shortName.end() ){
00197 std::cerr << "name " << sn << " already used !" << std::endl;
00198 exit( 1 );
00199 }
00200
00201 if( ln.size()>0 && longName.find(ln) != longName.end() ){
00202 std::cerr << "name " << ln << " already used !" << std::endl;
00203 exit( 1 );
00204 }
00205
00206 if( sho!=0 && sho == helpShortName ){
00207 std::cerr << "name " << sho << " reserved for help !" << std::endl;
00208 exit( 1 );
00209 }
00210 if( ln.size()>0 && lon == helpLongName ){
00211 std::cerr << "name " << lon << " reserved for help !" << std::endl;
00212 exit( 1 );
00213 }
00214
00215 ArgumentBase* c = new Argument<T>(ptr,sho,ln,h,false);
00216 shortName[sho] = c;
00217 longName[lon] = c;
00218 commands.push_back(c);
00219 return (*this);
00220 }
00221
00228 template<class T> inline
00229 ArgumentParser& parameter( T* ptr, char sho, char* lon, char* help )
00230 {
00231 string sn, ln(lon), h(help); sn += sho;
00232
00233 if( sho!=0 && shortName.find(sho) != shortName.end() ){
00234 std::cerr << "name " << sn << " already used !" << std::endl;
00235 exit( 1 );
00236 }
00237
00238 if( ln.size()>0 && longName.find(ln) != longName.end() ){
00239 std::cerr << "name " << ln << " already used !" << std::endl;
00240 exit( 1 );
00241 }
00242
00243 if( sho!=0 && sho == helpShortName ){
00244 std::cerr << "name " << sho << " reserved for help !" << std::endl;
00245 exit( 1 );
00246 }
00247 if( ln.size()>0 && lon == helpLongName ){
00248 std::cerr << "name " << lon << " reserved for help !" << std::endl;
00249 exit( 1 );
00250 }
00251
00252 ArgumentBase* c = new Argument<T>(ptr,sho,ln,h,true);
00253 shortName[sho] = c;
00254 longName[lon] = c;
00255 commands.push_back(c);
00256 return (*this);
00257 }
00258
00259
00264 inline void operator () ( int argc, char** argv )
00265 {
00266 string cmdLine;
00267 for( int i=1; i<argc; ++i )
00268 cmdLine += string( argv[i] ) + " ";
00269
00270 istrstream str( cmdLine.c_str() );
00271 (*this)( str );
00272
00273 }
00274
00275
00278 inline void operator () ( std::istream& str )
00279 {
00280
00281 string shHelp("-"); shHelp.push_back( helpShortName );
00282 string lgHelp("--"); lgHelp.append( helpLongName );
00283 string name;
00284 while( str>>name ){
00285
00286
00287
00288
00289
00290 if( name == shHelp || name == lgHelp )
00291 {
00292 if( globalHelp.size()>0 ) std::cout<< globalHelp <<std::endl;
00293 std::cout << "(short name, long name, description, default value)\n-h,\t--help: this help" << std::endl;
00294 for( ArgVec::const_iterator a=commands.begin(), aend=commands.end(); a!=aend; ++a )
00295 (*a)->print();
00296 exit(1);
00297 }
00298
00299
00300 else if( name.length() > 1 && name[0]=='-' && name[1]=='-' ){
00301 string a;
00302 for( unsigned int i=2; i<name.length(); ++i ){
00303 a += name[i];
00304 }
00305 if( longName.find(a) != longName.end() ){
00306 if( !(longName[ a ]->read( str )))
00307 std::cerr<< "\ncould not read value for option " << name << std::endl << std::endl;
00308 else parameter_set[longName[ a ]] = true;
00309 }
00310 else std::cerr << "\nUnknown option " << name << std::endl << std::endl;
00311 }
00312
00313
00314 else if( name.length() > 1 && name[0]=='-' && name[1]!='-' ){
00315 for( unsigned int i=1; i<name.length(); ++i ){
00316 char a = name[i];
00317 if( shortName.find(a) != shortName.end() ){
00318 if( !(shortName[ a ]->read( str )))
00319 std::cerr<< "\ncould not read value for option " << name << std::endl << std::endl;
00320 else parameter_set[shortName[ a ]] = true;
00321 }
00322 else std::cerr << "\nUnknown option " << name[i] << std::endl << std::endl;
00323 }
00324 }
00325
00326
00327 else std::cerr << "Unknown option " << name << std::endl;
00328 }
00329
00330
00331 bool unset = false;
00332 for( ArgVec::const_iterator cm = commands.begin(), cmend=commands.end(); cm != cmend; ++cm )
00333 {
00334 if( (*cm)->mandatory && !(*cm)->isSet ){
00335 if( !unset )
00336 {
00337 std::cout << "Please set the following parameters: (short name, long name, description)" << std::endl;
00338 unset = true;
00339 }
00340 (*cm)->print();
00341 }
00342 }
00343 if( unset ) exit(1);
00344 }
00345
00346 };
00359 inline ArgumentParser parse( const std::string& helpstr="", char hs='h', const std::string& hl="help" ){
00360 return ArgumentParser(helpstr,hs,hl);
00361 }
00362
00363 }
00364
00365
00366
00367 #endif
00368