|
- // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
-
- /******************************************************************************
- *
- * file: CmdLine.h
- *
- * Copyright (c) 2003, Michael E. Smoot .
- * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
- * All rights reserved.
- *
- * See the file COPYING in the top directory of this distribution for
- * more information.
- *
- * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- *****************************************************************************/
-
- #ifndef TCLAP_CMDLINE_H
- #define TCLAP_CMDLINE_H
-
- #include <tclap/SwitchArg.h>
- #include <tclap/MultiSwitchArg.h>
- #include <tclap/UnlabeledValueArg.h>
- #include <tclap/UnlabeledMultiArg.h>
-
- #include <tclap/XorHandler.h>
- #include <tclap/HelpVisitor.h>
- #include <tclap/VersionVisitor.h>
- #include <tclap/IgnoreRestVisitor.h>
-
- #include <tclap/CmdLineOutput.h>
- #include <tclap/StdOutput.h>
-
- #include <tclap/Constraint.h>
- #include <tclap/ValuesConstraint.h>
-
- #include <string>
- #include <vector>
- #include <list>
- #include <iostream>
- #include <iomanip>
- #include <algorithm>
- #include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
-
- namespace TCLAP
- {
-
- template<typename T>
- void DelPtr(T ptr)
- {
- delete ptr;
- }
-
- template<typename C>
- void ClearContainer(C& c)
- {
- typedef typename C::value_type value_type;
- std::for_each(c.begin(), c.end(), DelPtr<value_type>);
- c.clear();
- }
-
- /**
- * The base class that manages the command line definition and passes
- * along the parsing to the appropriate Arg classes.
- */
- class CmdLine : public CmdLineInterface
- {
- protected:
- /**
- * The list of arguments that will be tested against the
- * command line.
- */
- std::list<Arg*> _argList;
-
- /**
- * The name of the program. Set to argv[0].
- */
- std::string _progName;
-
- /**
- * A message used to describe the program. Used in the usage output.
- */
- std::string _message;
-
- /**
- * The version to be displayed with the --version switch.
- */
- std::string _version;
-
- /**
- * The number of arguments that are required to be present on
- * the command line. This is set dynamically, based on the
- * Args added to the CmdLine object.
- */
- int _numRequired;
-
- /**
- * The character that is used to separate the argument flag/name
- * from the value. Defaults to ' ' (space).
- */
- char _delimiter;
-
- /**
- * The handler that manages xoring lists of args.
- */
- XorHandler _xorHandler;
-
- /**
- * A list of Args to be explicitly deleted when the destructor
- * is called. At the moment, this only includes the three default
- * Args.
- */
- std::list<Arg*> _argDeleteOnExitList;
-
- /**
- * A list of Visitors to be explicitly deleted when the destructor
- * is called. At the moment, these are the Visitors created for the
- * default Args.
- */
- std::list<Visitor*> _visitorDeleteOnExitList;
-
- /**
- * Object that handles all output for the CmdLine.
- */
- CmdLineOutput* _output;
-
- /**
- * Should CmdLine handle parsing exceptions internally?
- */
- bool _handleExceptions;
-
- /**
- * Throws an exception listing the missing args.
- */
- void missingArgsException();
-
- /**
- * Checks whether a name/flag string matches entirely matches
- * the Arg::blankChar. Used when multiple switches are combined
- * into a single argument.
- * \param s - The message to be used in the usage.
- */
- bool _emptyCombined(const std::string& s);
-
- /**
- * Perform a delete ptr; operation on ptr when this object is deleted.
- */
- void deleteOnExit(Arg* ptr);
-
- /**
- * Perform a delete ptr; operation on ptr when this object is deleted.
- */
- void deleteOnExit(Visitor* ptr);
-
- private:
- /**
- * Prevent accidental copying.
- */
- CmdLine(const CmdLine& rhs);
- CmdLine& operator=(const CmdLine& rhs);
-
- /**
- * Encapsulates the code common to the constructors
- * (which is all of it).
- */
- void _constructor();
-
- /**
- * Is set to true when a user sets the output object. We use this so
- * that we don't delete objects that are created outside of this lib.
- */
- bool _userSetOutput;
-
- /**
- * Whether or not to automatically create help and version switches.
- */
- bool _helpAndVersion;
-
- /**
- * Whether or not to ignore unmatched args.
- */
- bool _ignoreUnmatched;
-
- public:
- /**
- * Command line constructor. Defines how the arguments will be
- * parsed.
- * \param message - The message to be used in the usage
- * output.
- * \param delimiter - The character that is used to separate
- * the argument flag/name from the value. Defaults to ' ' (space).
- * \param version - The version number to be used in the
- * --version switch.
- * \param helpAndVersion - Whether or not to create the Help and
- * Version switches. Defaults to true.
- */
- CmdLine(const std::string& message, const char delimiter = ' ', const std::string& version = "none", bool helpAndVersion = true);
-
- /**
- * Deletes any resources allocated by a CmdLine object.
- */
- virtual ~CmdLine();
-
- /**
- * Adds an argument to the list of arguments to be parsed.
- * \param a - Argument to be added.
- */
- void add(Arg& a);
-
- /**
- * An alternative add. Functionally identical.
- * \param a - Argument to be added.
- */
- void add(Arg* a);
-
- /**
- * Add two Args that will be xor'd. If this method is used, add does
- * not need to be called.
- * \param a - Argument to be added and xor'd.
- * \param b - Argument to be added and xor'd.
- */
- void xorAdd(Arg& a, Arg& b);
-
- /**
- * Add a list of Args that will be xor'd. If this method is used,
- * add does not need to be called.
- * \param xors - List of Args to be added and xor'd.
- */
- void xorAdd(const std::vector<Arg*>& xors);
-
- /**
- * Parses the command line.
- * \param argc - Number of arguments.
- * \param argv - Array of arguments.
- */
- void parse(int argc, const char* const* argv);
-
- /**
- * Parses the command line.
- * \param args - A vector of strings representing the args.
- * args[0] is still the program name.
- */
- void parse(std::vector<std::string>& args);
-
- /**
- *
- */
- 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();
-
- /**
- * Disables or enables CmdLine's internal parsing exception handling.
- *
- * @param state Should CmdLine handle parsing exceptions internally?
- */
- void setExceptionHandling(const bool state);
-
- /**
- * Returns the current state of the internal exception handling.
- *
- * @retval true Parsing exceptions are handled internally.
- * @retval false Parsing exceptions are propagated to the caller.
- */
- bool getExceptionHandling() const;
-
- /**
- * Allows the CmdLine object to be reused.
- */
- void reset();
-
- /**
- * Allows unmatched args to be ignored. By default false.
- *
- * @param ignore If true the cmdline will ignore any unmatched args
- * and if false it will behave as normal.
- */
- void ignoreUnmatched(const bool ignore);
- };
-
- ///////////////////////////////////////////////////////////////////////////////
- // Begin CmdLine.cpp
- ///////////////////////////////////////////////////////////////////////////////
-
- inline CmdLine::CmdLine(const std::string& m, char delim, const std::string& v, bool help) :
- _argList(std::list<Arg*>()),
- _progName("not_set_yet"),
- _message(m),
- _version(v),
- _numRequired(0),
- _delimiter(delim),
- _xorHandler(XorHandler()),
- _argDeleteOnExitList(std::list<Arg*>()),
- _visitorDeleteOnExitList(std::list<Visitor*>()),
- _output(0),
- _handleExceptions(true),
- _userSetOutput(false),
- _helpAndVersion(help),
- _ignoreUnmatched(false)
- {
- _constructor();
- }
-
- inline CmdLine::~CmdLine()
- {
- ClearContainer(_argDeleteOnExitList);
- ClearContainer(_visitorDeleteOnExitList);
-
- if (!_userSetOutput)
- {
- delete _output;
- _output = 0;
- }
- }
-
- 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(const 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, const char* const* argv)
- {
- // this step is necessary so that we have easy access to
- // mutable strings.
- std::vector<std::string> args;
- for (int i = 0; i < argc; i++)
- args.push_back(argv[i]);
-
- parse(args);
- }
-
- inline void CmdLine::parse(std::vector<std::string>& args)
- {
- bool shouldExit = false;
- int estat = 0;
- try
- {
- if (args.empty())
- {
- // https://sourceforge.net/p/tclap/bugs/30/
- throw CmdLineParseException("The args vector must not be empty, "
- "the first entry should contain the "
- "program's name.");
- }
-
- _progName = args.front();
- args.erase(args.begin());
-
- 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() && !_ignoreUnmatched)
- throw(CmdLineParseException("Couldn't find match "
- "for argument",
- args[i]));
- }
-
- if (requiredCount < _numRequired)
- missingArgsException();
-
- if (requiredCount > _numRequired)
- throw(CmdLineParseException("Too many arguments!"));
- }
- catch (ArgException& e)
- {
- // If we're not handling the exceptions, rethrow.
- if (!_handleExceptions)
- {
- throw;
- }
-
- try
- {
- _output->failure(*this, e);
- }
- catch (ExitException& ee)
- {
- estat = ee.getExitStatus();
- shouldExit = true;
- }
- }
- catch (ExitException& ee)
- {
- // If we're not handling the exceptions, rethrow.
- if (!_handleExceptions)
- {
- throw;
- }
-
- estat = ee.getExitStatus();
- shouldExit = true;
- }
-
- if (shouldExit)
- exit(estat);
- }
-
- inline bool CmdLine::_emptyCombined(const std::string& s)
- {
- if (s.length() > 0 && 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::missingArgsException()
- {
- int count = 0;
-
- std::string missingArgList;
- for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
- {
- if ((*it)->isRequired() && !(*it)->isSet())
- {
- missingArgList += (*it)->getName();
- missingArgList += ", ";
- count++;
- }
- }
- missingArgList = missingArgList.substr(0, missingArgList.length() - 2);
-
- std::string msg;
- if (count > 1)
- msg = "Required arguments missing: ";
- else
- msg = "Required argument missing: ";
-
- msg += missingArgList;
-
- throw(CmdLineParseException(msg));
- }
-
- 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)
- {
- if (!_userSetOutput)
- delete _output;
- _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;
- }
-
- inline void CmdLine::setExceptionHandling(const bool state)
- {
- _handleExceptions = state;
- }
-
- inline bool CmdLine::getExceptionHandling() const
- {
- return _handleExceptions;
- }
-
- inline void CmdLine::reset()
- {
- for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
- (*it)->reset();
-
- _progName.clear();
- }
-
- inline void CmdLine::ignoreUnmatched(const bool ignore)
- {
- _ignoreUnmatched = ignore;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // End CmdLine.cpp
- ///////////////////////////////////////////////////////////////////////////////
-
- } // namespace TCLAP
- #endif
|