Main MRPT website > C++ reference
MRPT logo

MultiArg.h

Go to the documentation of this file.
00001 /****************************************************************************** 
00002  * 
00003  *  file:  MultiArg.h
00004  * 
00005  *  Copyright (c) 2003, Michael E. Smoot .
00006  *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
00007  *  All rights reverved.
00008  * 
00009  *  See the file COPYING in the top directory of this distribution for
00010  *  more information.
00011  *  
00012  *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
00013  *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
00014  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
00015  *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
00016  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
00017  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
00018  *  DEALINGS IN THE SOFTWARE.  
00019  *  
00020  *****************************************************************************/
00021 
00022 
00023 #ifndef TCLAP_MULTIPLE_ARGUMENT_H
00024 #define TCLAP_MULTIPLE_ARGUMENT_H
00025 
00026 #include <string>
00027 #include <vector>
00028 
00029 #include <mrpt/otherlibs/tclap/Arg.h>
00030 #include <mrpt/otherlibs/tclap/Constraint.h>
00031 
00032 //#ifdef HAVE_CONFIG_H
00033 //#include <config.h>
00034 //#else
00035 #define HAVE_SSTREAM
00036 //#endif
00037 
00038 #if defined(HAVE_SSTREAM)
00039 #include <sstream>
00040 #elif defined(HAVE_STRSTREAM)
00041 #include <strstream>
00042 #else
00043 #error "Need a stringstream (sstream or strstream) to compile!"
00044 #endif
00045 
00046 namespace TCLAP {
00047 
00048 template<class T> class MultiArg;
00049 
00050 namespace MULTI_ARG_HELPER {
00051 
00052 enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };
00053 
00054 /**
00055  * This class is used to extract a value from an argument. 
00056  * It is used because we need a special implementation to
00057  * deal with std::string and making a specialiced function
00058  * puts it in the T segment, thus generating link errors.
00059  * Having a specialiced class makes the symbols weak.
00060  * This is not pretty but I don't know how to make it
00061  * work any other way.
00062  */
00063 template<class T>
00064 class ValueExtractor 
00065 {
00066         friend class MultiArg<T>;
00067   
00068         private:
00069 
00070                 /**
00071                  * Reference to the vector of values where the result of the 
00072                  * extraction will be put.
00073                  */
00074                 std::vector<T> &_values;
00075   
00076                 /**
00077                  * Constructor.
00078                  * \param values - Where the values extracted will be put.
00079                  */
00080                 ValueExtractor(std::vector<T> &values) : _values(values) {}
00081   
00082                 /**
00083                  * Method that will attempt to parse the input stream for values
00084                  * of type T.
00085                  * \param val - Where the values parsed will be put.
00086                  */
00087                 int extractValue( const std::string& val ) 
00088                 {
00089                         T temp;
00090 
00091 #if defined(HAVE_SSTREAM)
00092                         std::istringstream is(val);
00093 #elif defined(HAVE_STRSTREAM)
00094                         std::istrstream is(val.c_str());
00095 #else
00096 #error "Need a stringstream (sstream or strstream) to compile!"
00097 #endif
00098 
00099                         int valuesRead = 0;
00100     
00101                         while ( is.good() ) 
00102                         {
00103                                 if ( is.peek() != EOF )
00104                                         is >> temp; 
00105                                 else
00106                                         break;
00107       
00108                                 valuesRead++;
00109                         }               
00110     
00111                         if ( is.fail() )
00112                                 return EXTRACT_FAILURE;
00113     
00114                         if ( valuesRead > 1 )
00115                                 return EXTRACT_TOO_MANY;
00116     
00117                         _values.push_back(temp);
00118     
00119                         return 0;
00120                 } 
00121 };
00122 
00123 /**
00124  * Specialization for string.  This is necessary because istringstream
00125  * operator>> is not able to ignore spaces...  meaning -x "X Y" will only 
00126  * read 'X'... and thus the specialization.
00127  */
00128 template<>
00129 class ValueExtractor<std::string> 
00130 {
00131         friend class MultiArg<std::string>;
00132 
00133         private:
00134 
00135                 /**
00136                  * Reference to the vector of strings where the result of the 
00137                  * extraction will be put.
00138                  */
00139         std::vector<std::string> &_values;
00140   
00141                 /**
00142                  * Constructor.
00143                  * \param values - Where the strings extracted will be put.
00144                  */
00145         ValueExtractor(std::vector<std::string> &values) : _values(values) {}
00146 
00147                 /**
00148                  * Method that will attempt to parse the input stream for values
00149                  * of type std::string.
00150                  * \param val - Where the values parsed will be put.
00151                  */
00152         int extractValue( const std::string& val ) 
00153                 {
00154             _values.push_back( val );
00155             return 0;
00156         }
00157 };
00158 
00159 } //namespace MULTI_ARG_HELPER
00160 
00161 /**
00162  * An argument that allows multiple values of type T to be specified.  Very
00163  * similar to a ValueArg, except a vector of values will be returned
00164  * instead of just one.
00165  */
00166 template<class T>
00167 class MultiArg : public Arg
00168 {
00169         protected:
00170 
00171                 /**
00172                  * The list of values parsed from the CmdLine.
00173                  */
00174                 std::vector<T> _values;
00175 
00176                 /**
00177                  * The description of type T to be used in the usage.
00178                  */
00179                 std::string _typeDesc;
00180 
00181                 /**
00182                  * A list of constraint on this Arg. 
00183                  */
00184                 Constraint<T>* _constraint;
00185 
00186                 /**
00187                  * Extracts the value from the string.
00188                  * Attempts to parse string as type T, if this fails an exception
00189                  * is thrown.
00190                  * \param val - The string to be read.
00191                  */
00192                 void _extractValue( const std::string& val );
00193 
00194                 bool _allowMore;
00195 
00196         public:
00197 
00198                 /**
00199                  * Constructor.
00200                  * \param flag - The one character flag that identifies this
00201                  * argument on the command line.
00202                  * \param name - A one word name for the argument.  Can be
00203                  * used as a long flag on the command line.
00204                  * \param desc - A description of what the argument is for or
00205                  * does.
00206                  * \param req - Whether the argument is required on the command
00207                  * line.
00208                  * \param typeDesc - A short, human readable description of the
00209                  * type that this object expects.  This is used in the generation
00210                  * of the USAGE statement.  The goal is to be helpful to the end user
00211                  * of the program.
00212                  * \param v - An optional visitor.  You probably should not
00213                  * use this unless you have a very good reason.
00214                  */
00215                 MultiArg( const std::string& flag,
00216                   const std::string& name,
00217                   const std::string& desc,
00218                   bool req,
00219                   const std::string& typeDesc,
00220                   Visitor* v = NULL);
00221 
00222                 /**
00223                  * Constructor.
00224                  * \param flag - The one character flag that identifies this
00225                  * argument on the command line.
00226                  * \param name - A one word name for the argument.  Can be
00227                  * used as a long flag on the command line.
00228                  * \param desc - A description of what the argument is for or
00229                  * does.
00230                  * \param req - Whether the argument is required on the command
00231                  * line.
00232                  * \param typeDesc - A short, human readable description of the
00233                  * type that this object expects.  This is used in the generation
00234                  * of the USAGE statement.  The goal is to be helpful to the end user
00235                  * of the program.
00236                  * \param parser - A CmdLine parser object to add this Arg to
00237                  * \param v - An optional visitor.  You probably should not
00238                  * use this unless you have a very good reason.
00239                  */
00240                 MultiArg( const std::string& flag, 
00241                   const std::string& name,
00242                   const std::string& desc,
00243                   bool req,
00244                   const std::string& typeDesc,
00245                   CmdLineInterface& parser,
00246                   Visitor* v = NULL );
00247 
00248                 /**
00249                  * Constructor.
00250                  * \param flag - The one character flag that identifies this
00251                  * argument on the command line.
00252                  * \param name - A one word name for the argument.  Can be
00253                  * used as a long flag on the command line.
00254                  * \param desc - A description of what the argument is for or
00255                  * does.
00256                  * \param req - Whether the argument is required on the command
00257                  * line.
00258                  * \param constraint - A pointer to a Constraint object used
00259                  * to constrain this Arg.
00260                  * \param v - An optional visitor.  You probably should not
00261                  * use this unless you have a very good reason.
00262                  */
00263                 MultiArg( const std::string& flag,
00264                   const std::string& name,
00265                   const std::string& desc,
00266                   bool req,
00267                   Constraint<T>* constraint,
00268                   Visitor* v = NULL );
00269                   
00270                 /**
00271                  * Constructor.
00272                  * \param flag - The one character flag that identifies this
00273                  * argument on the command line.
00274                  * \param name - A one word name for the argument.  Can be
00275                  * used as a long flag on the command line.
00276                  * \param desc - A description of what the argument is for or
00277                  * does.
00278                  * \param req - Whether the argument is required on the command
00279                  * line.
00280                  * \param constraint - A pointer to a Constraint object used
00281                  * to constrain this Arg.
00282                  * \param parser - A CmdLine parser object to add this Arg to
00283                  * \param v - An optional visitor.  You probably should not
00284                  * use this unless you have a very good reason.
00285                  */
00286                 MultiArg( const std::string& flag, 
00287                   const std::string& name,
00288                   const std::string& desc,
00289                   bool req,
00290                   Constraint<T>* constraint,
00291                   CmdLineInterface& parser,
00292                   Visitor* v = NULL );
00293                   
00294                 /**
00295                  * Handles the processing of the argument.
00296                  * This re-implements the Arg version of this method to set the
00297                  * _value of the argument appropriately.  It knows the difference
00298                  * between labeled and unlabeled.
00299                  * \param i - Pointer the the current argument in the list.
00300                  * \param args - Mutable list of strings. Passed from main().
00301                  */
00302                 virtual bool processArg(int* i, std::vector<std::string>& args); 
00303 
00304                 /**
00305                  * Returns a vector of type T containing the values parsed from
00306                  * the command line.
00307                  */
00308                 const std::vector<T>& getValue();
00309 
00310                 /**
00311                  * Returns the a short id string.  Used in the usage. 
00312                  * \param val - value to be used.
00313                  */
00314                 virtual std::string shortID(const std::string& val="val") const;
00315 
00316                 /**
00317                  * Returns the a long id string.  Used in the usage. 
00318                  * \param val - value to be used.
00319                  */
00320                 virtual std::string longID(const std::string& val="val") const;
00321 
00322                 /**
00323                  * Once we've matched the first value, then the arg is no longer
00324                  * required.
00325                  */
00326                 virtual bool isRequired() const;
00327 
00328                 virtual bool allowMore();
00329 
00330 };
00331 
00332 template<class T>
00333 MultiArg<T>::MultiArg(const std::string& flag, 
00334                       const std::string& name,
00335                       const std::string& desc,
00336                       bool req,
00337                       const std::string& typeDesc,
00338                       Visitor* v)
00339 : Arg( flag, name, desc, req, true, v ),
00340   _typeDesc( typeDesc ),
00341   _constraint( NULL ),
00342   _allowMore(false)
00343 { 
00344         _acceptsMultipleValues = true;
00345 }
00346 
00347 template<class T>
00348 MultiArg<T>::MultiArg(const std::string& flag, 
00349                       const std::string& name,
00350                       const std::string& desc,
00351                       bool req,
00352                       const std::string& typeDesc,
00353                       CmdLineInterface& parser,
00354                       Visitor* v)
00355 : Arg( flag, name, desc, req, true, v ),
00356   _typeDesc( typeDesc ),
00357   _constraint( NULL ),
00358   _allowMore(false)
00359 { 
00360         parser.add( this );
00361         _acceptsMultipleValues = true;
00362 }
00363 
00364 /**
00365  *
00366  */
00367 template<class T>
00368 MultiArg<T>::MultiArg(const std::string& flag, 
00369                       const std::string& name,
00370                       const std::string& desc,
00371                       bool req,
00372                       Constraint<T>* constraint,
00373                       Visitor* v)
00374 : Arg( flag, name, desc, req, true, v ),
00375   _typeDesc( constraint->shortID() ),
00376   _constraint( constraint ),
00377   _allowMore(false)
00378 { 
00379         _acceptsMultipleValues = true;
00380 }
00381 
00382 template<class T>
00383 MultiArg<T>::MultiArg(const std::string& flag, 
00384                       const std::string& name,
00385                       const std::string& desc,
00386                       bool req,
00387                       Constraint<T>* constraint,
00388                       CmdLineInterface& parser,
00389                       Visitor* v)
00390 : Arg( flag, name, desc, req, true, v ),
00391   _typeDesc( constraint->shortID() ),
00392   _constraint( constraint ),
00393   _allowMore(false)
00394 { 
00395         parser.add( this );
00396         _acceptsMultipleValues = true;
00397 }
00398 
00399 template<class T>
00400 const std::vector<T>& MultiArg<T>::getValue() { return _values; }
00401 
00402 template<class T>
00403 bool MultiArg<T>::processArg(int *i, std::vector<std::string>& args) 
00404 {
00405         if ( _ignoreable && Arg::ignoreRest() )
00406                 return false;
00407 
00408         if ( _hasBlanks( args[*i] ) )
00409                 return false;
00410 
00411         std::string flag = args[*i];
00412         std::string value = "";
00413 
00414         trimFlag( flag, value );
00415 
00416         if ( argMatches( flag ) )
00417         {
00418                 if ( Arg::delimiter() != ' ' && value == "" )
00419                         throw( ArgParseException( 
00420                                    "Couldn't find delimiter for this argument!",
00421                                            toString() ) );
00422 
00423                 // always take the first one, regardless of start string
00424                 if ( value == "" )
00425                 {
00426                         (*i)++;
00427                         if ( static_cast<unsigned int>(*i) < args.size() )
00428                                 _extractValue( args[*i] );
00429                         else
00430                                 throw( ArgParseException("Missing a value for this argument!",
00431                                          toString() ) );
00432                 } 
00433                 else
00434                         _extractValue( value );
00435 
00436                 /*
00437                 // continuing taking the args until we hit one with a start string 
00438                 while ( (unsigned int)(*i)+1 < args.size() &&
00439                                 args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
00440                         args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) 
00441                                 _extractValue( args[++(*i)] );
00442                 */
00443 
00444                 _alreadySet = true;
00445                 _checkWithVisitor();
00446 
00447                 return true;
00448         }
00449         else
00450                 return false;
00451 }
00452 
00453 /**
00454  *
00455  */
00456 template<class T>
00457 std::string MultiArg<T>::shortID(const std::string& val) const
00458 {
00459         std::string id = Arg::shortID(_typeDesc) + " ... ";
00460 
00461         return id;
00462 }
00463 
00464 /**
00465  *
00466  */
00467 template<class T>
00468 std::string MultiArg<T>::longID(const std::string& val) const
00469 {
00470         std::string id = Arg::longID(_typeDesc) + "  (accepted multiple times)";
00471 
00472         return id;
00473 }
00474 
00475 /**
00476  * Once we've matched the first value, then the arg is no longer
00477  * required.
00478  */
00479 template<class T>
00480 bool MultiArg<T>::isRequired() const
00481 {
00482         if ( _required )
00483         {
00484                 if ( _values.size() > 1 )
00485                         return false;
00486                 else
00487                         return true;
00488         }
00489         else
00490                 return false;
00491 
00492 }
00493 
00494 template<class T>
00495 void MultiArg<T>::_extractValue( const std::string& val ) 
00496 {
00497         MULTI_ARG_HELPER::ValueExtractor<T> ve(_values);
00498                   
00499         int err = ve.extractValue(val);
00500 
00501         if ( err == MULTI_ARG_HELPER::EXTRACT_FAILURE )
00502                 throw( ArgParseException("Couldn't read argument value "
00503                                  "from string '" + val + "'", toString() ) );
00504 
00505         if(err == MULTI_ARG_HELPER::EXTRACT_TOO_MANY)
00506             throw( ArgParseException("More than one valid value "
00507                                  "parsed from string '" + val + "'", 
00508                                                                  toString() ) );                    
00509         if ( _constraint != NULL )
00510                 if ( ! _constraint->check( _values.back() ) )
00511                         throw( CmdLineParseException( "Value '" + val +
00512                                           "' does not meet constraint: " +
00513                                           _constraint->description(), 
00514                                                                                   toString() ) );
00515 }
00516                 
00517 template<class T>
00518 bool MultiArg<T>::allowMore()
00519 {
00520         bool am = _allowMore;
00521         _allowMore = true;
00522         return am;
00523 }
00524 
00525 } // namespace TCLAP
00526 
00527 #endif



Page generated by Doxygen 1.7.3 for MRPT 0.9.4 SVN: at Sat Mar 26 06:16:28 UTC 2011