diff --git a/include/tclap/Arg.h b/include/tclap/Arg.h index ea3f7fc..718d51d 100644 --- a/include/tclap/Arg.h +++ b/include/tclap/Arg.h @@ -507,7 +507,7 @@ inline void Arg::trimFlag(std::string& flag, std::string& value) const { int stop = 0; for ( int i = 0; (unsigned int)i < flag.length(); i++ ) - if ( flag[i] == delimiter() ) + if ( flag[i] == Arg::delimiter() ) { stop = i; break; diff --git a/include/tclap/CmdLine.h b/include/tclap/CmdLine.h index e0499d8..b54343a 100644 --- a/include/tclap/CmdLine.h +++ b/include/tclap/CmdLine.h @@ -32,10 +32,15 @@ #include #include +#include +#include + #include #include #include #include +#include +#include #include namespace TCLAP { @@ -100,7 +105,12 @@ class CmdLine : public CmdLineInterface * default Args. */ std::list _visitorDeleteOnExitList; - + + /** + * Object that handles all output for the CmdLine. + */ + CmdLineOutput* _output; + /** * Checks whether a name/flag string matches entirely matches * the Arg::blankChar. Used when multiple switches are combined @@ -109,19 +119,6 @@ class CmdLine : public CmdLineInterface */ bool _emptyCombined(const std::string& s); - /** - * Writes a brief usage message with short args. - * \param os - The stream to write the message to. - */ - void _shortUsage( std::ostream& os ); - - /** - * Writes a longer usage message with long and short args, - * provides descriptions and prints message. - * \param os - The stream to write the message to. - */ - void _longUsage( std::ostream& os ); - private: /** @@ -202,33 +199,52 @@ class CmdLine : public CmdLineInterface */ void xorAdd( std::vector& xors ); - /** - * Prints the usage to stdout and exits. Can be overridden to - * produce alternative behavior. - * \param exitVal - Value to exit with. - */ - virtual void usage( int exitVal = 0 ); - - /** - * Prints the version to stdout and exits. Can be overridden - * to produce alternative behavior. - * \param exitVal - Value to exit with. - */ - virtual void version( int exitVal = 0 ); - - /** - * Prints (to stderr) an error message, short usage and exits with a - * value of 1. Can be overridden to produce alternative behavior. - * \param e - The ArgException that caused the failure. - */ - virtual void failure( const ArgException& e ); - /** * Parses the command line. * \param argc - Number of arguments. * \param argv - Array of arguments. */ void parse(int argc, char** argv); + + /** + * + */ + CmdLineOutput* getOutput(); + + /** + * + */ + void setOutput(CmdLineOutput* co); + + /** + * + */ + std::string& getVersion(); + + /** + * + */ + std::string& getProgramName(); + + /** + * + */ + std::list& getArgList(); + + /** + * + */ + XorHandler& getXorHandler(); + + /** + * + */ + char getDelimiter(); + + /** + * + */ + std::string& getMessage(); }; @@ -278,23 +294,25 @@ inline CmdLine::~CmdLine() inline void CmdLine::_constructor() { + _output = new StdOutput; + Visitor *v; Arg::setDelimiter( _delimiter ); - v = new HelpVisitor( this ); + v = new HelpVisitor( this, _output ); SwitchArg* help = new SwitchArg("h","help", "Displays usage information and exits.", false, v); - add( *help ); + add( help ); deleteOnExit(help); deleteOnExit(v); - v = new VersionVisitor( this ); + v = new VersionVisitor( this, _output ); SwitchArg* vers = new SwitchArg("v","version", "Displays version information and exits.", false, v); - add( *vers ); + add( vers ); deleteOnExit(vers); deleteOnExit(v); @@ -303,7 +321,7 @@ inline void CmdLine::_constructor() Arg::ignoreNameString(), "Ignores the rest of the labeled arguments following this flag.", false, v); - add( *ignore ); + add( ignore ); deleteOnExit(ignore); deleteOnExit(v); } @@ -344,72 +362,8 @@ inline void CmdLine::add( Arg* a ) a->addToList( _argList ); - if ( a->isRequired() ) _numRequired++; -} - -inline void CmdLine::version(int exitVal) -{ - std::cout << std::endl << _progName << " version: " - << _version << std::endl << std::endl; - exit( exitVal ); -} - -inline void CmdLine::_shortUsage( std::ostream& os ) -{ - std::string s = _progName + " " + _xorHandler.shortUsage(); - - for (ArgIterator it = _argList.begin(); it != _argList.end(); it++) - if ( !_xorHandler.contains( (*it) ) ) - s += " " + (*it)->shortID(); - - spacePrint( os, s, 75, 3, (int)(_progName.length()) + 2 ); -} - -inline void CmdLine::_longUsage( std::ostream& os ) -{ - _xorHandler.printLongUsage( os ); - - for (ArgIterator it = _argList.begin(); it != _argList.end(); it++) - if ( !_xorHandler.contains( (*it) ) ) - { - spacePrint( os, (*it)->longID(), 75, 3, 3 ); - spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); - os << std::endl; - } - - os << std::endl; - spacePrint( os, _message, 75, 3, 0 ); -} - -inline void CmdLine::usage( int exitVal ) -{ - std::cout << std::endl << "USAGE: " << std::endl << std::endl; - - _shortUsage( std::cout ); - - std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl; - - _longUsage( std::cout ); - - std::cout << std::endl; - - exit( exitVal ); -} - -inline void CmdLine::failure( const ArgException& e ) -{ - std::cerr << "PARSE ERROR: " << e.argId() << std::endl - << " " << e.error() << std::endl << std::endl; - - std::cerr << "Brief USAGE: " << std::endl; - - _shortUsage( std::cerr ); - - std::cerr << std::endl << "For complete USAGE and HELP type: " - << std::endl << " " << _progName << " --help" - << std::endl << std::endl; - - exit(1); + if ( a->isRequired() ) + _numRequired++; } inline void CmdLine::parse(int argc, char** argv) @@ -454,7 +408,7 @@ inline void CmdLine::parse(int argc, char** argv) if ( requiredCount > _numRequired ) throw(CmdLineParseException("Too many arguments!")); - } catch ( ArgException& e ) { failure(e); } + } catch ( ArgException e ) { _output->failure(*this,e); exit(1); } } inline bool CmdLine::_emptyCombined(const std::string& s) @@ -479,6 +433,46 @@ inline void CmdLine::deleteOnExit(Visitor* ptr) _visitorDeleteOnExitList.push_back(ptr); } +inline CmdLineOutput* CmdLine::getOutput() +{ + return _output; +} + +inline void CmdLine::setOutput(CmdLineOutput* co) +{ + _output = co; +} + +inline std::string& CmdLine::getVersion() +{ + return _version; +} + +inline std::string& CmdLine::getProgramName() +{ + return _progName; +} + +inline std::list& CmdLine::getArgList() +{ + return _argList; +} + +inline XorHandler& CmdLine::getXorHandler() +{ + return _xorHandler; +} + +inline char CmdLine::getDelimiter() +{ + return _delimiter; +} + +inline std::string& CmdLine::getMessage() +{ + return _message; +} + /////////////////////////////////////////////////////////////////////////////// //End CmdLine.cpp /////////////////////////////////////////////////////////////////////////////// diff --git a/include/tclap/CmdLineInterface.h b/include/tclap/CmdLineInterface.h index b5852aa..b4542e0 100644 --- a/include/tclap/CmdLineInterface.h +++ b/include/tclap/CmdLineInterface.h @@ -1,4 +1,3 @@ -/* -*- Mode: CC; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /****************************************************************************** * @@ -30,9 +29,12 @@ #include #include + namespace TCLAP { class Arg; +class CmdLineOutput; +class XorHandler; /** * The base class that manages the command line definition and passes @@ -75,31 +77,52 @@ class CmdLineInterface */ virtual void xorAdd( std::vector& xors )=0; - /** - * Prints the usage to stdout and exits. - * \param exitVal - Value to exit with. - */ - virtual void usage( int exitVal = 0 )=0; - - /** - * Prints the version to stdout and exits. - * \param exitVal - Value to exit with. - */ - virtual void version( int exitVal = 0 )=0; - - /** - * Prints (to stderr) an error message, short usage and exits with a - * value of 1. Can be overridden to produce alternative behavior. - * \param e - The ArgException that caused the failure. - */ - virtual void failure( const ArgException& e )=0; - /** * Parses the command line. * \param argc - Number of arguments. * \param argv - Array of arguments. */ virtual void parse(int argc, char** argv)=0; + + /** + * Returns the CmdLineOutput object. + */ + virtual CmdLineOutput* getOutput()=0; + + /** + * \param co - CmdLineOutput object that we want to use instead. + */ + virtual void setOutput(CmdLineOutput* co)=0; + + /** + * Returns the version string. + */ + virtual std::string& getVersion()=0; + + /** + * Returns the program name string. + */ + virtual std::string& getProgramName()=0; + + /** + * Returns the argList. + */ + virtual std::list& getArgList()=0; + + /** + * Returns the XorHandler. + */ + virtual XorHandler& getXorHandler()=0; + + /** + * Returns the delimiter string. + */ + virtual char getDelimiter()=0; + + /** + * Returns the message string. + */ + virtual std::string& getMessage()=0; }; } //namespace diff --git a/include/tclap/CmdLineOutput.h b/include/tclap/CmdLineOutput.h new file mode 100644 index 0000000..c2a7043 --- /dev/null +++ b/include/tclap/CmdLineOutput.h @@ -0,0 +1,69 @@ + + +/****************************************************************************** + * + * file: CmdLineOutput.h + * + * Copyright (c) 2004, Michael E. Smoot + * 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_CMDLINEOUTPUT_H +#define TCLAP_CMDLINEOUTPUT_H + +#include +#include +#include +#include +#include +#include +#include + +namespace TCLAP { + +class CmdLineInterface; +class ArgException; + +/** + * The interface that any output object must implement. + */ +class CmdLineOutput +{ + + public: + /** + * Generates some sort of output for the USAGE. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c)=0; + + /** + * Generates some sort of output for the version. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c)=0; + + /** + * Generates some sort of output for a failure. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure( CmdLineInterface& c, + ArgException& e )=0; + +}; + +} //namespace TCLAP +#endif diff --git a/include/tclap/HelpVisitor.h b/include/tclap/HelpVisitor.h index a12b48e..fc1fe1f 100644 --- a/include/tclap/HelpVisitor.h +++ b/include/tclap/HelpVisitor.h @@ -23,34 +23,44 @@ #define TCLAP_HELP_VISITOR_H #include +#include #include namespace TCLAP { /** - * A Visitor object that calls the usage method of a given CmdLine. + * A Visitor object that calls the usage method of the given CmdLineOutput + * object for the specified CmdLine object. */ class HelpVisitor: public Visitor { protected: /** - * The CmdLine that will be called for the usage method. + * The CmdLine the output will be generated for. */ CmdLineInterface* _cmd; + /** + * The output object. + */ + CmdLineOutput* _out; + public: /** * Constructor. - * \param cmd - The CmdLine that will called for usage method. + * \param cmd - The CmdLine the output will be generated for. + * \param out - The type of output. */ - HelpVisitor(CmdLineInterface* cmd) : Visitor(), _cmd( cmd ) { } + HelpVisitor(CmdLineInterface* cmd, CmdLineOutput* out) + : Visitor(), _cmd( cmd ), _out( out ) { } /** - * Calls the usage method of the CmdLine. + * Calls the usage method of the CmdLineOutput for the + * specified CmdLine. */ - void visit() { _cmd->usage(0); } + void visit() { _out->usage(*_cmd); exit(0); } }; diff --git a/include/tclap/Makefile.am b/include/tclap/Makefile.am index 3aa8fe0..d1a60a0 100644 --- a/include/tclap/Makefile.am +++ b/include/tclap/Makefile.am @@ -15,5 +15,6 @@ libtclapinclude_HEADERS = \ SwitchArg.h \ VersionVisitor.h \ IgnoreRestVisitor.h \ - PrintSensibly.h + CmdLineOutput.h \ + StdOutput.h diff --git a/include/tclap/StdOutput.h b/include/tclap/StdOutput.h new file mode 100644 index 0000000..4e253f0 --- /dev/null +++ b/include/tclap/StdOutput.h @@ -0,0 +1,275 @@ + +/****************************************************************************** + * + * file: StdOutput.h + * + * Copyright (c) 2004, Michael E. Smoot + * 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_STDCMDLINEOUTPUT_H +#define TCLAP_STDCMDLINEOUTPUT_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A class that isolates any output from the CmdLine object so that it + * may be easily modified. + */ +class StdOutput : public CmdLineOutput +{ + + public: + + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); + + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); + + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); + + protected: + + /** + * Writes a brief usage message with short args. + * \param c - The CmdLine object the output is generated for. + * \param os - The stream to write the message to. + */ + void _shortUsage( CmdLineInterface& c, std::ostream& os ) const; + + /** + * Writes a longer usage message with long and short args, + * provides descriptions and prints message. + * \param c - The CmdLine object the output is generated for. + * \param os - The stream to write the message to. + */ + void _longUsage( CmdLineInterface& c, std::ostream& os ) const; + + /** + * This function inserts line breaks and indents long strings + * according the params input. It will only break lines at spaces, + * commas and pipes. + * \param os - The stream to be printed to. + * \param s - The string to be printed. + * \param maxWidth - The maxWidth allowed for the output line. + * \param indentSpaces - The number of spaces to indent the first line. + * \param secondLineOffset - The number of spaces to indent the second + * and all subsequent lines in addition to indentSpaces. + */ + void spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces=0, + int secondLineOffset=0 ) const; + +}; + + +inline void StdOutput::version(CmdLineInterface& _cmd) +{ + std::string progName = _cmd.getProgramName(); + std::string version = _cmd.getVersion(); + + std::cout << std::endl << progName << " version: " + << version << std::endl << std::endl; +} + +inline void StdOutput::usage(CmdLineInterface& _cmd ) +{ + std::cout << std::endl << "USAGE: " << std::endl << std::endl; + + _shortUsage( _cmd, std::cout ); + + std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl; + + _longUsage( _cmd, std::cout ); + + std::cout << std::endl; + +} + +inline void StdOutput::failure( CmdLineInterface& _cmd, + ArgException& e ) +{ + std::string progName = _cmd.getProgramName(); + + std::cerr << "PARSE ERROR: " << e.argId() << std::endl + << " " << e.error() << std::endl << std::endl; + + std::cerr << "Brief USAGE: " << std::endl; + + _shortUsage( _cmd, std::cerr ); + + std::cerr << std::endl << "For complete USAGE and HELP type: " + << std::endl << " " << progName << " --help" + << std::endl << std::endl; + +} + +inline void StdOutput::_shortUsage( CmdLineInterface& _cmd, + std::ostream& os ) const +{ + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + + std::string s = progName + " "; + + // first the xor + for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) + { + s += " {"; + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); it++ ) + s += (*it)->shortID() + "|"; + + s[s.length()-1] = '}'; + } + + // then the rest + for (ArgIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + s += " " + (*it)->shortID(); + + spacePrint( std::cout, s, 75, 3, (int)(progName.length()) + 2 ); +} + +inline void StdOutput::_longUsage( CmdLineInterface& _cmd, + std::ostream& os ) const +{ + std::list argList = _cmd.getArgList(); + std::string message = _cmd.getMessage(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + + // first the xor + for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) + { + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); + it++ ) + { + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); + + if ( it+1 != xorList[i].end() ) + spacePrint(os, "-- OR --", 75, 9); + } + os << std::endl << std::endl; + } + + // then the rest + for (ArgIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + { + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); + os << std::endl; + } + + os << std::endl; + + spacePrint( os, message, 75, 3, 0 ); +} + +inline void StdOutput::spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces, + int secondLineOffset ) const +{ + int len = (int)(s.length()); + + if ( (len + indentSpaces > maxWidth) && maxWidth > 0 ) + { + int allowedLen = maxWidth - indentSpaces; + int start = 0; + while ( start < len ) + { + // find the substring length + int stringLen = std::min( len - start, allowedLen ); + + // trim the length so it doesn't end in middle of a word + if ( stringLen == allowedLen ) + while ( s[stringLen+start] != ' ' && + s[stringLen+start] != ',' && + s[stringLen+start] != '|' ) + stringLen--; + + // check for newlines + for ( int i = 0; i < stringLen; i++ ) + if ( s[start+i] == '\n' ) + stringLen = i+1; + + // print the indent + for ( int i = 0; i < indentSpaces; i++ ) + os << " "; + + if ( start == 0 ) + { + // handle second line offsets + indentSpaces += secondLineOffset; + + // adjust allowed len + allowedLen -= secondLineOffset; + } + + os << s.substr(start,stringLen) << std::endl; + + // so we don't start a line with a space + if ( s[stringLen+start] == ' ' ) + start++; + + start += stringLen; + } + } + else + { + for ( int i = 0; i < indentSpaces; i++ ) + os << " "; + os << s << std::endl; + } +} + +} //namespace TCLAP +#endif diff --git a/include/tclap/VersionVisitor.h b/include/tclap/VersionVisitor.h index 3199874..8d2bd07 100644 --- a/include/tclap/VersionVisitor.h +++ b/include/tclap/VersionVisitor.h @@ -24,13 +24,14 @@ #define TCLAP_VERSION_VISITOR_H #include +#include #include namespace TCLAP { /** - * A Vistor that will call the version method of the given CmdLine and - * then exit. + * A Vistor that will call the version method of the given CmdLineOutput + * for the specified CmdLine object and then exit. */ class VersionVisitor: public Visitor { @@ -40,19 +41,27 @@ class VersionVisitor: public Visitor * The CmdLine of interest. */ CmdLineInterface* _cmd; - + + /** + * The output object. + */ + CmdLineOutput* _out; + public: /** * Constructor. - * \param cmd - The CmdLine whose version method will be called. + * \param cmd - The CmdLine the output is generated for. + * \param out - The type of output. */ - VersionVisitor(CmdLineInterface* cmd) : Visitor(), _cmd( cmd ) { } + VersionVisitor( CmdLineInterface* cmd, CmdLineOutput* out ) + : Visitor(), _cmd( cmd ), _out( out ) { } /** - * Prints the version to stdout. + * Calls the version method of the output object using the + * specified CmdLine. */ - void visit() { _cmd->version(0); } + void visit() { _out->version(*_cmd); exit(0); } }; } diff --git a/include/tclap/XorHandler.h b/include/tclap/XorHandler.h index 152bc52..4e66368 100644 --- a/include/tclap/XorHandler.h +++ b/include/tclap/XorHandler.h @@ -24,7 +24,6 @@ #define TCLAP_XORHANDLER_H #include -#include #include #include #include @@ -85,6 +84,8 @@ class XorHandler */ bool contains( const Arg* a ); + std::vector< std::vector >& getXorList(); + }; @@ -96,6 +97,7 @@ inline void XorHandler::add( std::vector& ors ) _orList.push_back( ors ); } +/* inline std::string XorHandler::shortUsage() { std::string out = ""; @@ -129,7 +131,7 @@ inline void XorHandler::printLongUsage( std::ostream& os ) os << std::endl << std::endl; } } - +*/ inline int XorHandler::check( const Arg* a ) { // iterate over each XOR list @@ -168,6 +170,14 @@ inline bool XorHandler::contains( const Arg* a ) return false; } + +inline std::vector< std::vector >& XorHandler::getXorList() +{ + return _orList; +} + + + ////////////////////////////////////////////////////////////////////// //END XOR.cpp //////////////////////////////////////////////////////////////////////