603 lines
17 KiB
C++
603 lines
17 KiB
C++
// -*- 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 reverved.
|
|
*
|
|
* 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 Vistors 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;
|
|
|
|
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(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();
|
|
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//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) {
|
|
_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(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 {
|
|
_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())
|
|
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();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//End CmdLine.cpp
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
} //namespace TCLAP
|
|
#endif
|