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 program is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU General Public License as published by the Free  *
00007 * Software Foundation; either version 2 of the License, or (at your option)   *
00008 * any later version.                                                          *
00009 *                                                                             *
00010 * This program 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 General Public License for    *
00013 * more details.                                                               *
00014 *                                                                             *
00015 * You should have received a copy of the GNU General Public License along     *
00016 * with this program; if not, write to the Free Software Foundation, Inc., 51  *
00017 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
00018 *******************************************************************************
00019 *                            SOFA :: Applications                             *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 //========================================================
00028 // Yet another command line parser. 
00029 // Fran�is Faure, iMAGIS-GRAVIR, May 2001
00030 //========================================================
00031 
00032 #ifndef ANIMAL_command_line_parser________
00033 #define ANIMAL_command_line_parser________
00034 
00035 #include <iostream>
00036 #include <stdlib.h>
00037 //#include <strstream>
00038 #include <sstream>
00039 #include <fstream>
00040 #include <string>
00041 #include <vector>
00042 #include <algorithm>
00043 #include <map>
00044 #include <list>
00045 
00046 typedef std::istringstream istrstream; 
00047 
00049 struct ArgumentBase
00050 {
00052     typedef std::string string;
00053     
00060     ArgumentBase(char s, string l, string h, bool m)
00061         : shortName(s)
00062         , longName(l)
00063         , help(h)
00064         , mandatory(m)
00065         , isSet(false)
00066     {}
00067     
00069     virtual ~ArgumentBase(){}
00070 
00072     virtual bool read( std::list<std::string>& str ) = 0;
00073     
00075     virtual void printValue() const =0;
00076 
00077     char shortName; 
00078     string longName;  
00079     string help;      
00080     
00082     inline void print () const
00083     {
00084         std::cout << "-" << shortName <<",\t--"<< longName <<":\t" << help;
00085         if( mandatory ) std::cout<< " (required) ";
00086         std::cout << "  (default: "; printValue();
00087         std::cout << ")" << std::endl;
00088     }
00089 
00091     bool mandatory;
00092 
00094     bool isSet;
00095     
00096 
00097 };
00098 
00099 
00100 //=========================================================================
00101 
00109 template < class T = void* >
00110 struct Argument : public ArgumentBase {
00111 
00112     
00120     Argument( T* t, char sn, string ln, string h, bool m )
00121         : ArgumentBase(sn,ln,h,m)
00122         , ptr(t)
00123     {}
00124     
00125     inline void printValue() const ;
00126     
00127 private:
00129     T* ptr;
00130     
00131     
00135     inline bool read( std::list<std::string>& str ) {
00136         if (str.empty()) return false;
00137         std::string s = str.front();
00138         str.pop_front();
00139         istrstream istr( s.c_str() );
00140         if( ! (istr >> *ptr) ) return false;
00141         else {
00142             isSet = true;
00143             return true;
00144         }
00145     }
00146     
00147 };
00148 
00155 template<> inline 
00156 bool Argument<bool>::read( std::list<std::string>& )
00157 {
00158     *ptr = true;
00159     isSet = true;
00160     return true;
00161 }
00162 
00163 template<> inline 
00164         bool Argument<std::string>::read( std::list<std::string>& str )
00165 {
00166     if (str.empty()) return false;
00167     std::string s = str.front();
00168     str.pop_front();
00169     *ptr = s;
00170     isSet = true;
00171     return true;
00172 }
00173 
00175 template<class T> inline
00176 void Argument<T>::printValue() const {
00177     std::cout << *ptr << " ";
00178 }
00179 
00180 
00181 //========================================================================
00182 
00192 class ArgumentParser {
00194     typedef std::string string;
00196     typedef std::map< string, ArgumentBase* > Map;
00198     std::map< char, ArgumentBase* > shortName;
00200     Map longName;
00201     
00203     typedef std::map<ArgumentBase*,bool> SetMap;
00204     
00206     SetMap parameter_set;
00207     
00209     typedef std::vector<ArgumentBase*> ArgVec;
00211     ArgVec commands;
00212     
00213     // help stuff
00214     string globalHelp;    
00215     char helpShortName;   
00216     string helpLongName;  
00217 
00218 public:
00219 
00221     ArgumentParser( const string& helpstr="", char hlpShrt='h', const string& hlpLng="help" )
00222         : globalHelp( helpstr )
00223         , helpShortName(hlpShrt)
00224         , helpLongName(hlpLng)
00225     {}
00226     
00233     template<class T> inline 
00234     ArgumentParser& option( T* ptr, char sho, char* lon, char* help )
00235     {
00236         string sn, ln(lon), h(help); sn += sho;
00237         
00238         if( sho!=0 && shortName.find(sho) != shortName.end() ){
00239             std::cerr << "name " << sn << " already used !" << std::endl;
00240             exit( 1 );
00241         }
00242         
00243         if( ln.size()>0 && longName.find(ln) != longName.end() ){
00244             std::cerr << "name " << ln << " already used !" << std::endl;
00245             exit( 1 );
00246         }
00247         
00248         if( sho!=0 && sho == helpShortName ){
00249             std::cerr << "name " << sho << " reserved for help !" << std::endl;
00250             exit( 1 );
00251         }
00252         if( ln.size()>0 && lon == helpLongName ){
00253             std::cerr << "name " << lon << " reserved for help !" << std::endl;
00254             exit( 1 );
00255         }
00256         
00257         ArgumentBase* c = new Argument<T>(ptr,sho,ln,h,false);
00258         shortName[sho] = c; 
00259         longName[lon] = c; 
00260         commands.push_back(c);
00261         return (*this);
00262     }
00263     
00270     template<class T> inline 
00271     ArgumentParser& parameter( T* ptr, char sho, char* lon, char* help )
00272     {
00273         string sn, ln(lon), h(help); sn += sho;
00274         
00275         if( sho!=0 && shortName.find(sho) != shortName.end() ){
00276             std::cerr << "name " << sn << " already used !" << std::endl;
00277             exit( 1 );
00278         }
00279         
00280         if( ln.size()>0 && longName.find(ln) != longName.end() ){
00281             std::cerr << "name " << ln << " already used !" << std::endl;
00282             exit( 1 );
00283         }
00284         
00285         if( sho!=0 && sho == helpShortName ){
00286             std::cerr << "name " << sho << " reserved for help !" << std::endl;
00287             exit( 1 );
00288         }
00289         if( ln.size()>0 && lon == helpLongName ){
00290             std::cerr << "name " << lon << " reserved for help !" << std::endl;
00291             exit( 1 );
00292         }
00293         
00294         ArgumentBase* c = new Argument<T>(ptr,sho,ln,h,true);
00295         shortName[sho] = c; 
00296         longName[lon] = c; 
00297         commands.push_back(c);
00298         return (*this);
00299     }
00300 
00301 
00306     inline void operator () ( int argc, char** argv )
00307     {
00308         std::list<std::string> str;
00309         for (int i=1;i<argc;++i)
00310             str.push_back(std::string(argv[i]));
00311         (*this)(str);
00312     }
00313 
00314     inline void operator () ( std::list<std::string> str )
00315     {
00316         string shHelp("-");  shHelp.push_back( helpShortName ); 
00317         string lgHelp("--"); lgHelp.append( helpLongName ); 
00318         string name;
00319         while( !str.empty() ){
00320             name = str.front();
00321             str.pop_front();
00322 //          std::cout << "name = " << name << std::endl;
00323 //          std::cout << "lgHelp = " << lgHelp << std::endl;
00324 //          std::cout << "shHelp = " << shHelp << std::endl;
00325             
00326             // display help
00327             if( name == shHelp || name == lgHelp )
00328             {
00329                 if( globalHelp.size()>0 ) std::cout<< globalHelp <<std::endl;
00330                 std::cout << "(short name, long name, description, default value)\n-h,\t--help: this help" << std::endl;
00331                 for( ArgVec::const_iterator a=commands.begin(), aend=commands.end(); a!=aend; ++a )
00332                     (*a)->print();
00333                 exit(1);
00334             }
00335             
00336             // long name
00337             else if( name.length() > 1 && name[0]=='-' && name[1]=='-' ){
00338                 string a;
00339                 for( unsigned int i=2; i<name.length(); ++i ){
00340                     a += name[i];
00341                 }
00342                 if( longName.find(a) != longName.end() ){
00343                     if( !(longName[ a ]->read( str ))) 
00344                         std::cerr<< "\ncould not read value for option " << name << std::endl << std::endl;
00345                     else parameter_set[longName[ a ]] = true;
00346                 }
00347                 else std::cerr << "\nUnknown option " << name << std::endl << std::endl;
00348             }
00349             
00350             // short names (possibly concatenated)
00351             else if( name.length() > 1 && name[0]=='-' && name[1]!='-' ){
00352                 for( unsigned int i=1; i<name.length(); ++i ){
00353                     char a = name[i];
00354                     if( shortName.find(a) != shortName.end() ){
00355                         if( !(shortName[ a ]->read( str ))) 
00356                             std::cerr<< "\ncould not read value for option " << name << std::endl << std::endl;
00357                         else parameter_set[shortName[ a ]] = true;
00358                     }
00359                     else std::cerr << "\nUnknown option " << name[i] << std::endl << std::endl;
00360                 }
00361             }
00362             
00363             //
00364             else std::cerr << "Unknown option " << name << std::endl;
00365         }
00366 
00367         // Unset mandatory arguments ?
00368         bool unset = false;
00369         for( ArgVec::const_iterator cm = commands.begin(), cmend=commands.end(); cm != cmend; ++cm )
00370         {
00371             if( (*cm)->mandatory && !(*cm)->isSet ){
00372                 if( !unset )
00373                 {
00374                     std::cout << "Please set the following parameters: (short name, long name, description)" << std::endl;
00375                     unset = true;
00376                 }
00377                 (*cm)->print();                 
00378             }
00379         }   
00380         if( unset ) exit(1);
00381     }
00382 
00383 };
00384 
00391 inline ArgumentParser parse( const std::string& helpstr="", char hs='h', const std::string& hl="help" ){ 
00392     return ArgumentParser(helpstr,hs,hl); 
00393 }
00394 
00395 
00396 
00397 
00398 #endif
00399 

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