argumentParser.h

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 //========================================================
00026 // Yet another command line parser. 
00027 // Fran�is Faure, iMAGIS-GRAVIR, May 2001
00028 //========================================================
00029 
00030 #ifndef ANIMAL_command_line_parser________
00031 #define ANIMAL_command_line_parser________
00032 
00033 #include <iostream>
00034 #include <stdlib.h>
00035 //#include <strstream>
00036 #include <sstream>
00037 #include <fstream>
00038 #include <string>
00039 #include <vector>
00040 #include <algorithm>
00041 #include <map>
00042 #include <list>
00043 
00044 typedef std::istringstream istrstream; 
00045 
00047 struct ArgumentBase
00048 {
00050     typedef std::string string;
00051     
00058     ArgumentBase(char s, string l, string h, bool m)
00059         : shortName(s)
00060         , longName(l)
00061         , help(h)
00062         , mandatory(m)
00063         , isSet(false)
00064     {}
00065     
00067     virtual ~ArgumentBase(){}
00068 
00070     virtual bool read( std::list<std::string>& str ) = 0;
00071     
00073     virtual void printValue() const =0;
00074 
00075     char shortName; 
00076     string longName;  
00077     string help;      
00078     
00080     inline void print () const
00081     {
00082         std::cout << "-" << shortName <<",\t--"<< longName <<":\t" << help;
00083         if( mandatory ) std::cout<< " (required) ";
00084         std::cout << "  (default: "; printValue();
00085         std::cout << ")" << std::endl;
00086     }
00087 
00089     bool mandatory;
00090 
00092     bool isSet;
00093     
00094 
00095 };
00096 
00097 
00098 //=========================================================================
00099 
00107 template < class T = void* >
00108 struct Argument : public ArgumentBase {
00109 
00110     
00118     Argument( T* t, char sn, string ln, string h, bool m )
00119         : ArgumentBase(sn,ln,h,m)
00120         , ptr(t)
00121     {}
00122     
00123     inline void printValue() const ;
00124     
00125 private:
00127     T* ptr;
00128     
00129     
00133     inline bool read( std::list<std::string>& str ) {
00134         if (str.empty()) return false;
00135         std::string s = str.front();
00136         str.pop_front();
00137         istrstream istr( s.c_str() );
00138         if( ! (istr >> *ptr) ) return false;
00139         else {
00140             isSet = true;
00141             return true;
00142         }
00143     }
00144     
00145 };
00146 
00153 template<> inline 
00154 bool Argument<bool>::read( std::list<std::string>& )
00155 {
00156     *ptr = true;
00157     isSet = true;
00158     return true;
00159 }
00160 
00161 template<> inline 
00162         bool Argument<std::string>::read( std::list<std::string>& str )
00163 {
00164     if (str.empty()) return false;
00165     std::string s = str.front();
00166     str.pop_front();
00167     *ptr = s;
00168     isSet = true;
00169     return true;
00170 }
00171 
00173 template<class T> inline
00174 void Argument<T>::printValue() const {
00175     std::cout << *ptr << " ";
00176 }
00177 
00178 
00179 //========================================================================
00180 
00190 class ArgumentParser {
00192     typedef std::string string;
00194     typedef std::map< string, ArgumentBase* > Map;
00196     std::map< char, ArgumentBase* > shortName;
00198     Map longName;
00199     
00201     typedef std::map<ArgumentBase*,bool> SetMap;
00202     
00204     SetMap parameter_set;
00205     
00207     typedef std::vector<ArgumentBase*> ArgVec;
00209     ArgVec commands;
00210     
00211     // help stuff
00212     string globalHelp;    
00213     char helpShortName;   
00214     string helpLongName;  
00215 
00216 public:
00217 
00219     ArgumentParser( const string& helpstr="", char hlpShrt='h', const string& hlpLng="help" )
00220         : globalHelp( helpstr )
00221         , helpShortName(hlpShrt)
00222         , helpLongName(hlpLng)
00223     {}
00224     
00231     template<class T> inline 
00232     ArgumentParser& option( T* ptr, char sho, char* lon, char* help )
00233     {
00234         string sn, ln(lon), h(help); sn += sho;
00235         
00236         if( sho!=0 && shortName.find(sho) != shortName.end() ){
00237             std::cerr << "name " << sn << " already used !" << std::endl;
00238             exit( 1 );
00239         }
00240         
00241         if( ln.size()>0 && longName.find(ln) != longName.end() ){
00242             std::cerr << "name " << ln << " already used !" << std::endl;
00243             exit( 1 );
00244         }
00245         
00246         if( sho!=0 && sho == helpShortName ){
00247             std::cerr << "name " << sho << " reserved for help !" << std::endl;
00248             exit( 1 );
00249         }
00250         if( ln.size()>0 && lon == helpLongName ){
00251             std::cerr << "name " << lon << " reserved for help !" << std::endl;
00252             exit( 1 );
00253         }
00254         
00255         ArgumentBase* c = new Argument<T>(ptr,sho,ln,h,false);
00256         shortName[sho] = c; 
00257         longName[lon] = c; 
00258         commands.push_back(c);
00259         return (*this);
00260     }
00261     
00268     template<class T> inline 
00269     ArgumentParser& parameter( T* ptr, char sho, char* lon, char* help )
00270     {
00271         string sn, ln(lon), h(help); sn += sho;
00272         
00273         if( sho!=0 && shortName.find(sho) != shortName.end() ){
00274             std::cerr << "name " << sn << " already used !" << std::endl;
00275             exit( 1 );
00276         }
00277         
00278         if( ln.size()>0 && longName.find(ln) != longName.end() ){
00279             std::cerr << "name " << ln << " already used !" << std::endl;
00280             exit( 1 );
00281         }
00282         
00283         if( sho!=0 && sho == helpShortName ){
00284             std::cerr << "name " << sho << " reserved for help !" << std::endl;
00285             exit( 1 );
00286         }
00287         if( ln.size()>0 && lon == helpLongName ){
00288             std::cerr << "name " << lon << " reserved for help !" << std::endl;
00289             exit( 1 );
00290         }
00291         
00292         ArgumentBase* c = new Argument<T>(ptr,sho,ln,h,true);
00293         shortName[sho] = c; 
00294         longName[lon] = c; 
00295         commands.push_back(c);
00296         return (*this);
00297     }
00298 
00299 
00304     inline void operator () ( int argc, char** argv )
00305     {
00306         std::list<std::string> str;
00307         for (int i=1;i<argc;++i)
00308             str.push_back(std::string(argv[i]));
00309         (*this)(str);
00310     }
00311 
00312     inline void operator () ( std::list<std::string> str )
00313     {
00314         string shHelp("-");  shHelp.push_back( helpShortName ); 
00315         string lgHelp("--"); lgHelp.append( helpLongName ); 
00316         string name;
00317         while( !str.empty() ){
00318             name = str.front();
00319             str.pop_front();
00320 //          std::cout << "name = " << name << std::endl;
00321 //          std::cout << "lgHelp = " << lgHelp << std::endl;
00322 //          std::cout << "shHelp = " << shHelp << std::endl;
00323             
00324             // display help
00325             if( name == shHelp || name == lgHelp )
00326             {
00327                 if( globalHelp.size()>0 ) std::cout<< globalHelp <<std::endl;
00328                 std::cout << "(short name, long name, description, default value)\n-h,\t--help: this help" << std::endl;
00329                 for( ArgVec::const_iterator a=commands.begin(), aend=commands.end(); a!=aend; ++a )
00330                     (*a)->print();
00331                 exit(1);
00332             }
00333             
00334             // long name
00335             else if( name.length() > 1 && name[0]=='-' && name[1]=='-' ){
00336                 string a;
00337                 for( unsigned int i=2; i<name.length(); ++i ){
00338                     a += name[i];
00339                 }
00340                 if( longName.find(a) != longName.end() ){
00341                     if( !(longName[ a ]->read( str ))) 
00342                         std::cerr<< "\ncould not read value for option " << name << std::endl << std::endl;
00343                     else parameter_set[longName[ a ]] = true;
00344                 }
00345                 else std::cerr << "\nUnknown option " << name << std::endl << std::endl;
00346             }
00347             
00348             // short names (possibly concatenated)
00349             else if( name.length() > 1 && name[0]=='-' && name[1]!='-' ){
00350                 for( unsigned int i=1; i<name.length(); ++i ){
00351                     char a = name[i];
00352                     if( shortName.find(a) != shortName.end() ){
00353                         if( !(shortName[ a ]->read( str ))) 
00354                             std::cerr<< "\ncould not read value for option " << name << std::endl << std::endl;
00355                         else parameter_set[shortName[ a ]] = true;
00356                     }
00357                     else std::cerr << "\nUnknown option " << name[i] << std::endl << std::endl;
00358                 }
00359             }
00360             
00361             //
00362             else std::cerr << "Unknown option " << name << std::endl;
00363         }
00364 
00365         // Unset mandatory arguments ?
00366         bool unset = false;
00367         for( ArgVec::const_iterator cm = commands.begin(), cmend=commands.end(); cm != cmend; ++cm )
00368         {
00369             if( (*cm)->mandatory && !(*cm)->isSet ){
00370                 if( !unset )
00371                 {
00372                     std::cout << "Please set the following parameters: (short name, long name, description)" << std::endl;
00373                     unset = true;
00374                 }
00375                 (*cm)->print();                 
00376             }
00377         }   
00378         if( unset ) exit(1);
00379     }
00380 
00381 };
00382 
00389 inline ArgumentParser parse( const std::string& helpstr="", char hs='h', const std::string& hl="help" ){ 
00390     return ArgumentParser(helpstr,hs,hl); 
00391 }
00392 
00393 
00394 
00395 
00396 #endif
00397 

Generated on Sun Nov 23 03:50:11 2008 for Sofa by  doxygen 1.5.7.1