Program Listing for File value_arg.hpp

Return to documentation for file (include/ecl/command_line/value_arg.hpp)

/*****************************************************************************
** Ifdefs
*****************************************************************************/

#ifndef TCLAP_VALUE_ARGUMENT_H
#define TCLAP_VALUE_ARGUMENT_H

#include <string>
#include <vector>
#include <cstdio>
#include "arg.hpp"
#include "constraint.hpp"

#define HAVE_SSTREAM

#if defined(HAVE_SSTREAM)
#include <sstream>
#elif defined(HAVE_STRSTREAM)
#include <strstream>
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif

namespace ecl {

template<class T> class ValueArg;

namespace ValueArgHelper {

enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };

template<class T> class ValueExtractor
{
    friend class ValueArg<T>;

    private:

        T &_value;

        ValueExtractor(T &value) : _value(value) { }

        int extractValue( const std::string& val )
        {

#if defined(HAVE_SSTREAM)
            std::istringstream is(val);
#elif defined(HAVE_STRSTREAM)
            std::istrstream is(val.c_str());
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif

            int valuesRead = 0;
            while ( is.good() )
            {
                if ( is.peek() != EOF )
                    is >> _value;
                else
                    break;

                valuesRead++;
            }

            if ( is.fail() )
                return EXTRACT_FAILURE;

            if ( valuesRead > 1 )
                return EXTRACT_TOO_MANY;

            return 0;
        }
};

template<> class ValueExtractor<std::string>
{
    friend class ValueArg<std::string>;

    private:

        std::string &_value;

        ValueExtractor(std::string &value) : _value(value) {}

        int extractValue( const std::string& val )
        {
            _value = val;
            return 0;
        }
};

} //namespace ValueArgHelper

template<class T>
class ValueArg : public Arg
{
    protected:

        T _value;

        std::string _typeDesc;

        Constraint<T>* _constraint;

        void _extractValue( const std::string& val );

    public:

        ValueArg( const std::string& flag,
                  const std::string& name,
                  const std::string& desc,
                  bool req,
                  T value,
                  const std::string& typeDesc,
                  Visitor* v = NULL);


        ValueArg( const std::string& flag,
                  const std::string& name,
                  const std::string& desc,
                  bool req,
                  T value,
                  const std::string& typeDesc,
                  CmdLineInterface& parser,
                  Visitor* v = NULL );

        ValueArg( const std::string& flag,
                  const std::string& name,
                  const std::string& desc,
                  bool req,
                  T value,
                  Constraint<T>* constraint,
                  CmdLineInterface& parser,
                  Visitor* v = NULL );

        ValueArg( const std::string& flag,
                  const std::string& name,
                  const std::string& desc,
                  bool req,
                  T value,
                  Constraint<T>* constraint,
                  Visitor* v = NULL );

        virtual bool processArg(int* i, std::vector<std::string>& args);

        T& getValue() ;

        virtual std::string shortID(const std::string& val = "val") const;

        virtual std::string longID(const std::string& val = "val") const;

};


template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
                      const std::string& name,
                      const std::string& desc,
                      bool req,
                      T value,
                      const std::string& typeDesc,
                      Visitor* v)
: Arg(flag, name, desc, req, true, v),
  _value( value ),
  _typeDesc( typeDesc ),
  _constraint( NULL )
{ }

template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
                      const std::string& name,
                      const std::string& desc,
                      bool req,
                      T val,
                      const std::string& typeDesc,
                      CmdLineInterface& parser,
                      Visitor* v)
: Arg(flag, name, desc, req, true, v),
  _value( val ),
  _typeDesc( typeDesc ),
  _constraint( NULL )
{
    parser.add( this );
}

template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
                      const std::string& name,
                      const std::string& desc,
                      bool req,
                      T val,
                      Constraint<T>* constraint,
                      Visitor* v)
: Arg(flag, name, desc, req, true, v),
  _value( val ),
  _typeDesc( constraint->shortID() ),
  _constraint( constraint )
{ }

template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
                      const std::string& name,
                      const std::string& desc,
                      bool req,
                      T val,
                      Constraint<T>* constraint,
                      CmdLineInterface& parser,
                      Visitor* v)
: Arg(flag, name, desc, req, true, v),
  _value( val ),
  _typeDesc( constraint->shortID() ),
  _constraint( constraint )
{
    parser.add( this );
}


template<class T>
T& ValueArg<T>::getValue() { return _value; }

template<class T>
bool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)
{
    if ( _ignoreable && Arg::ignoreRest() )
        return false;

    if ( _hasBlanks( args[*i] ) )
        return false;

    std::string flag = args[*i];

    std::string value = "";
    trimFlag( flag, value );

    if ( argMatches( flag ) )
    {
        if ( _alreadySet )
            throw( CmdLineParseException("Argument already set!", toString()) );

        if ( Arg::delimiter() != ' ' && value == "" )
            throw( ArgParseException(
                            "Couldn't find delimiter for this argument!",
                             toString() ) );

        if ( value == "" )
        {
            (*i)++;
            if ( static_cast<unsigned int>(*i) < args.size() )
                _extractValue( args[*i] );
            else
                throw( ArgParseException("Missing a value for this argument!",
                                                    toString() ) );
        }
        else
            _extractValue( value );

        _alreadySet = true;
        _checkWithVisitor();
        return true;
    }
    else
        return false;
}

template<class T>
std::string ValueArg<T>::shortID(const std::string& val) const
{
    std::string stop_warnings = val; // Only to stop annoying warning messages, I dont think it slows things down
    return Arg::shortID( _typeDesc );
}

template<class T>
std::string ValueArg<T>::longID(const std::string& val) const
{
    std::string stop_warnings = val; // Only to stop annoying warning messages, I dont think it slows things down
    return Arg::longID( _typeDesc );
}

template<class T> // Just to stop the warnings.
void ValueArg<T>::_extractValue( const std::string& val )
{
    ValueArgHelper::ValueExtractor<T> ve(_value);

    int err = ve.extractValue(val);

    if ( err == ValueArgHelper::EXTRACT_FAILURE )
        throw( ArgParseException("Couldn't read argument value from string '" +
                                 val + "'", toString() ) );

    if ( err == ValueArgHelper::EXTRACT_TOO_MANY )
        throw( ArgParseException(
                    "More than one valid value parsed from string '" +
                    val + "'", toString() ) );

    if ( _constraint != NULL )
        if ( ! _constraint->check( _value ) )
            throw( CmdLineParseException( "Value '" + val +
                                          "' does not meet constraint: " +
                                          _constraint->description(),
                                          toString() ) );
}

} // namespace ecl

#endif