// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- /****************************************************************************** * * 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, int secondLineOffset ) const; }; inline void StdOutput::version(CmdLineInterface& _cmd) { std::string progName = _cmd.getProgramName(); std::string xversion = _cmd.getVersion(); std::cout << std::endl << progName << " version: " << xversion << 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; if ( _cmd.hasHelpAndVersion() ) { 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; } else usage(_cmd); throw ExitException(1); } 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; static_cast(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 (ArgListIterator it = argList.begin(); it != argList.end(); it++) if ( !xorHandler.contains( (*it) ) ) s += " " + (*it)->shortID(); // if the program name is too long, then adjust the second line offset int secondLineOffset = static_cast(progName.length()) + 2; if ( secondLineOffset > 75/2 ) secondLineOffset = static_cast(75/2); spacePrint( os, s, 75, 3, secondLineOffset ); } 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; static_cast(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, 0); } os << std::endl << std::endl; } // then the rest for (ArgListIterator 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 = static_cast(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 ); // doing it this way to support a VisualC++ 2005 bug using namespace std; int stringLen = min( len - start, allowedLen ); // trim the length so it doesn't end in middle of a word if ( stringLen == allowedLen ) while ( stringLen >= 0 && s[stringLen+start] != ' ' && s[stringLen+start] != ',' && s[stringLen+start] != '|' ) stringLen--; // ok, the word is longer than the line, so just split // wherever the line ends if ( stringLen <= 0 ) stringLen = allowedLen; // 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 while ( s[stringLen+start] == ' ' && start < len ) start++; start += stringLen; } } else { for ( int i = 0; i < indentSpaces; i++ ) os << " "; os << s << std::endl; } } } //namespace TCLAP #endif