Documentation


argumentParser.h

Go to the documentation of this file.
00001 //========================================================
00002 // Yet another command line parser. 
00003 // François Faure, iMAGIS-GRAVIR, May 2001
00004 //========================================================
00005 
00006 #ifndef ANIMAL_command_line_parser________
00007 #define ANIMAL_command_line_parser________
00008 
00009 #include <iostream>
00010 #include <stdlib.h>
00011 //#include <strstream>
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 // /// Partial specialization for printing default value
00136 // template<class T> inline
00137 // void Argument<T*>::printValue() const {}
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     // help stuff
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 //          std::cout << "name = " << name << std::endl;
00286 //          std::cout << "lgHelp = " << lgHelp << std::endl;
00287 //          std::cout << "shHelp = " << shHelp << std::endl;
00288             
00289             // display help
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             // long name
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             // short names (possibly concatenated)
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         // Unset mandatory arguments ?
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 } // close namespace animal
00364 
00365 
00366 
00367 #endif
00368 

Generated on Thu Dec 23 13:52:23 2004 by doxygen 1.3.6