Program Listing for File cmd_line.hpp

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

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

#ifndef TCLAP_CMDLINE_H
#define TCLAP_CMDLINE_H

#include "switch_arg.hpp"
#include "multi_switch_arg.hpp"
#include "unlabeled_value_arg.hpp"
#include "unlabeled_multi_arg.hpp"

#include "xor_handler.hpp"
#include "help_visitor.hpp"
#include "version_visitor.hpp"
#include "ignore_rest_visitor.hpp"

#include "cmd_line_output.hpp"
#include "std_output.hpp"

#include "constraint.hpp"
#include "values_constraint.hpp"

#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>
#include <algorithm>

namespace ecl {

class CmdLine : public CmdLineInterface
{
    protected:

        std::list<Arg*> _argList;

        std::string _progName;

        std::string _message;

        std::string _version;

        int _numRequired;

        char _delimiter;

        XorHandler _xorHandler;

        std::list<Arg*> _argDeleteOnExitList;

        std::list<Visitor*> _visitorDeleteOnExitList;

        CmdLineOutput* _output;

        bool _emptyCombined(const std::string& s);

        void deleteOnExit(Arg* ptr);

        void deleteOnExit(Visitor* ptr);

    private:

        void _constructor();

        bool _userSetOutput;

        bool _helpAndVersion;

    public:

        CmdLine(const std::string& message,
                const char delimiter = ' ',
                const std::string& version = "none",
                bool helpAndVersion = true);

        virtual ~CmdLine();

        void add( Arg& a );

        void add( Arg* a );

        void xorAdd( Arg& a, Arg& b );

        void xorAdd( std::vector<Arg*>& xors );

        void parse(int argc, char** argv);

        CmdLineOutput* getOutput();

        void setOutput(CmdLineOutput* co);

        std::string& getVersion();

        std::string& getProgramName();

        std::list<Arg*>& getArgList();

        XorHandler& getXorHandler();

        char getDelimiter();

        std::string& getMessage();

        bool hasHelpAndVersion();
};


//Begin CmdLine.cpp

inline CmdLine::CmdLine(const std::string& m,
                        char delim,
                        const std::string& v,
                        bool help )
: _progName("not_set_yet"),
  _message(m),
  _version(v),
  _numRequired(0),
  _delimiter(delim),
  _userSetOutput(false),
  _helpAndVersion(help)
{
    _constructor();
}

inline CmdLine::~CmdLine()
{
    ArgListIterator argIter;
    VisitorListIterator visIter;

    for( argIter = _argDeleteOnExitList.begin();
         argIter != _argDeleteOnExitList.end();
         ++argIter)
        delete *argIter;

    for( visIter = _visitorDeleteOnExitList.begin();
         visIter != _visitorDeleteOnExitList.end();
         ++visIter)
        delete *visIter;

    if ( !_userSetOutput )
        delete _output;
}

inline void CmdLine::_constructor()
{
    _output = new StdOutput;

    Arg::setDelimiter( _delimiter );

    Visitor* v;

    if ( _helpAndVersion )
    {
        v = new HelpVisitor( this, &_output );
        SwitchArg* help = new SwitchArg("h","help",
                        "Displays usage information and exits.",
                        false, v);
        add( help );
        deleteOnExit(help);
        deleteOnExit(v);

        v = new VersionVisitor( this, &_output );
        SwitchArg* vers = new SwitchArg("","version",
                    "Displays version information and exits.",
                    false, v);
        add( vers );
        deleteOnExit(vers);
        deleteOnExit(v);
    }

    v = new IgnoreRestVisitor();
    SwitchArg* ignore  = new SwitchArg(Arg::flagStartString(),
                       Arg::ignoreNameString(),
               "Ignores the rest of the labeled arguments following this flag.",
                       false, v);
    add( ignore );
    deleteOnExit(ignore);
    deleteOnExit(v);
}

inline void CmdLine::xorAdd( std::vector<Arg*>& ors )
{
    _xorHandler.add( ors );

    for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
    {
        (*it)->forceRequired();
        (*it)->setRequireLabel( "OR required" );

        add( *it );
    }
}

inline void CmdLine::xorAdd( Arg& a, Arg& b )
{
    std::vector<Arg*> ors;
    ors.push_back( &a );
    ors.push_back( &b );
    xorAdd( ors );
}

inline void CmdLine::add( Arg& a )
{
    add( &a );
}

inline void CmdLine::add( Arg* a )
{
    for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
        if ( *a == *(*it) )
            throw( SpecificationException(
                    "Argument with same flag/name already exists!",
                    a->longID() ) );

    a->addToList( _argList );

    if ( a->isRequired() )
        _numRequired++;
}

inline void CmdLine::parse(int argc, char** argv)
{
    try {

    _progName = argv[0];

    // this step is necessary so that we have easy access to mutable strings.
    std::vector<std::string> args;
    for (int i = 1; i < argc; i++)
        args.push_back(argv[i]);

    int requiredCount = 0;

    for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
    {
        bool matched = false;
        for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
        {
            if ( (*it)->processArg( &i, args ) )
            {
                requiredCount += _xorHandler.check( *it );
                matched = true;
                break;
            }
        }

        // checks to see if the argument is an empty combined switch ...
        // and if so, then we've actually matched it
        if ( !matched && _emptyCombined( args[i] ) )
            matched = true;

        if ( !matched && !Arg::ignoreRest() )
            throw(CmdLineParseException("Couldn't find match for argument",
                                         args[i]));
    }

    if ( requiredCount < _numRequired )
        throw(CmdLineParseException("One or more required arguments missing!"));

    if ( requiredCount > _numRequired )
        throw(CmdLineParseException("Too many arguments!"));

    } catch ( ArgException &e ) {
        _output->failure(*this, e); exit(1);
    }
}

inline bool CmdLine::_emptyCombined(const std::string& s)
{
    if ( s[0] != Arg::flagStartChar() )
        return false;

    for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
        if ( s[i] != Arg::blankChar() )
            return false;

    return true;
}

inline void CmdLine::deleteOnExit(Arg* ptr)
{
    _argDeleteOnExitList.push_back(ptr);
}

inline void CmdLine::deleteOnExit(Visitor* ptr)
{
    _visitorDeleteOnExitList.push_back(ptr);
}

inline CmdLineOutput* CmdLine::getOutput()
{
    return _output;
}

inline void CmdLine::setOutput(CmdLineOutput* co)
{
    _userSetOutput = true;
    _output = co;
}

inline std::string& CmdLine::getVersion()
{
    return _version;
}

inline std::string& CmdLine::getProgramName()
{
    return _progName;
}

inline std::list<Arg*>& CmdLine::getArgList()
{
    return _argList;
}

inline XorHandler& CmdLine::getXorHandler()
{
    return _xorHandler;
}

inline char CmdLine::getDelimiter()
{
    return _delimiter;
}

inline std::string& CmdLine::getMessage()
{
    return _message;
}

inline bool CmdLine::hasHelpAndVersion()
{
    return _helpAndVersion;
}

//End CmdLine.cpp

} // namespace ecl

#endif