Program Listing for File multi_arg.hpp

Return to documentation for file (/tmp/ws/src/ecl_core/ecl_command_line/include/ecl/command_line/multi_arg.hpp)

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

#ifndef TCLAP_MULTIPLE_ARGUMENT_H
#define TCLAP_MULTIPLE_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 MultiArg;

namespace MultiArgHelper {

enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };

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

    private:

        std::vector<T> &_values;

        ValueExtractor(std::vector<T> &values) : _values(values) {}

        int extractValue( const std::string& val )
        {
            T temp;

#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 >> temp;
                else
                    break;

                valuesRead++;
            }

            if ( is.fail() )
                return EXTRACT_FAILURE;

            if ( valuesRead > 1 )
                return EXTRACT_TOO_MANY;

            _values.push_back(temp);

            return 0;
        }
};

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

    private:

        std::vector<std::string> &_values;

        ValueExtractor(std::vector<std::string> &values) : _values(values) {}

        int extractValue( const std::string& val )
        {
            _values.push_back( val );
            return 0;
        }
};

} //namespace MultiArgHelper

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

        std::vector<T> _values;

        std::string _typeDesc;

        Constraint<T>* _constraint;

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

        bool _allowMore;

    public:

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

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

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

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

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

        const std::vector<T>& getValue();

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

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

        virtual bool isRequired() const;

        virtual bool allowMore();

};

template<class T>
MultiArg<T>::MultiArg(const std::string& flag,
                      const std::string& name,
                      const std::string& desc,
                      bool req,
                      const std::string& typeDesc,
                      Visitor* v)
: Arg( flag, name, desc, req, true, v ),
  _typeDesc( typeDesc ),
  _constraint( NULL ),
  _allowMore(false)
{
    _acceptsMultipleValues = true;
}

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

template<class T>
MultiArg<T>::MultiArg(const std::string& flag,
                      const std::string& name,
                      const std::string& desc,
                      bool req,
                      Constraint<T>* constraint,
                      Visitor* v)
: Arg( flag, name, desc, req, true, v ),
  _typeDesc( constraint->shortID() ),
  _constraint( constraint ),
  _allowMore(false)
{
    _acceptsMultipleValues = true;
}

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

template<class T>
const std::vector<T>& MultiArg<T>::getValue() { return _values; }

template<class T>
bool MultiArg<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 ( Arg::delimiter() != ' ' && value == "" )
            throw( ArgParseException(
                       "Couldn't find delimiter for this argument!",
                       toString() ) );

        // always take the first one, regardless of start string
        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 );

        /*
        // continuing taking the args until we hit one with a start string
        while ( (unsigned int)(*i)+1 < args.size() &&
                args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
                args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
                _extractValue( args[++(*i)] );
        */

        _alreadySet = true;
        _checkWithVisitor();

        return true;
    }
    else
        return false;
}

template<class T>
std::string MultiArg<T>::shortID(const std::string& /*val*/) const
{
    std::string id = Arg::shortID(_typeDesc) + " ... ";

    return id;
}

template<class T>
std::string MultiArg<T>::longID(const std::string& /*val*/) const
{
    std::string id = Arg::longID(_typeDesc) + "  (accepted multiple times)";

    return id;
}

template<class T>
bool MultiArg<T>::isRequired() const
{
    if ( _required )
    {
        if ( _values.size() > 1 )
            return false;
        else
            return true;
    }
    else
        return false;

}

template<class T>
void MultiArg<T>::_extractValue( const std::string& val )
{
    MultiArgHelper::ValueExtractor<T> ve(_values);

    int err = ve.extractValue(val);

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

    if(err == MultiArgHelper::EXTRACT_TOO_MANY)
        throw( ArgParseException("More than one valid value "
                                 "parsed from string '" + val + "'",
                                 toString() ) );
    if ( _constraint != NULL )
        if ( ! _constraint->check( _values.back() ) )
            throw( CmdLineParseException( "Value '" + val +
                                          "' does not meet constraint: " +
                                          _constraint->description(),
                                          toString() ) );
}

template<class T>
bool MultiArg<T>::allowMore()
{
    bool am = _allowMore;
    _allowMore = true;
    return am;
}

} // namespace ecl


#endif