BASIS  version 1.2.3 (revision 2104)
StdOutput.h
00001 // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
00002 
00003 /****************************************************************************** 
00004  * 
00005  *  file:  StdOutput.h
00006  * 
00007  *  Copyright (c) 2004, Michael E. Smoot
00008  *  All rights reverved.
00009  * 
00010  *  See the file COPYING in the top directory of this distribution for
00011  *  more information.
00012  *  
00013  *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
00014  *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
00015  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
00016  *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
00017  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
00018  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
00019  *  DEALINGS IN THE SOFTWARE.  
00020  *  
00021  *****************************************************************************/ 
00022 
00023 #ifndef TCLAP_STDCMDLINEOUTPUT_H
00024 #define TCLAP_STDCMDLINEOUTPUT_H
00025 
00026 #include <string>
00027 #include <vector>
00028 #include <list>
00029 #include <iostream>
00030 #include <algorithm>
00031 
00032 #include <sbia/tclap/CmdLineInterface.h>
00033 #include <sbia/tclap/CmdLineOutput.h>
00034 #include <sbia/tclap/XorHandler.h>
00035 #include <sbia/tclap/Arg.h>
00036 
00037 namespace TCLAP {
00038 
00039 /**
00040  * A class that isolates any output from the CmdLine object so that it
00041  * may be easily modified.
00042  */
00043 class StdOutput : public CmdLineOutput
00044 {
00045 
00046     public:
00047 
00048         /**
00049          * Prints the usage to stdout.  Can be overridden to 
00050          * produce alternative behavior.
00051          * \param c - The CmdLine object the output is generated for. 
00052          */
00053         virtual void usage(CmdLineInterface& c);
00054 
00055         /**
00056          * Prints the version to stdout. Can be overridden 
00057          * to produce alternative behavior.
00058          * \param c - The CmdLine object the output is generated for. 
00059          */
00060         virtual void version(CmdLineInterface& c);
00061 
00062         /**
00063          * Prints (to stderr) an error message, short usage 
00064          * Can be overridden to produce alternative behavior.
00065          * \param c - The CmdLine object the output is generated for. 
00066          * \param e - The ArgException that caused the failure. 
00067          */
00068         virtual void failure(CmdLineInterface& c, 
00069                      ArgException& e );
00070 
00071     protected:
00072 
00073         /**
00074          * Writes a brief usage message with short args.
00075          * \param c - The CmdLine object the output is generated for. 
00076          * \param os - The stream to write the message to.
00077          */
00078         void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;
00079 
00080         /**
00081          * Writes a longer usage message with long and short args, 
00082          * provides descriptions and prints message.
00083          * \param c - The CmdLine object the output is generated for. 
00084          * \param os - The stream to write the message to.
00085          */
00086         void _longUsage( CmdLineInterface& c, std::ostream& os ) const;
00087 
00088         /**
00089          * This function inserts line breaks and indents long strings 
00090          * according the  params input. It will only break lines at spaces, 
00091          * commas and pipes.
00092          * \param os - The stream to be printed to.
00093          * \param s - The string to be printed.
00094          * \param maxWidth - The maxWidth allowed for the output line. 
00095          * \param indentSpaces - The number of spaces to indent the first line. 
00096          * \param secondLineOffset - The number of spaces to indent the second
00097          * and all subsequent lines in addition to indentSpaces.
00098          */
00099         void spacePrint( std::ostream& os, 
00100                          const std::string& s, 
00101                          int maxWidth, 
00102                          int indentSpaces, 
00103                          int secondLineOffset ) const;
00104 
00105 };
00106 
00107 
00108 inline void StdOutput::version(CmdLineInterface& _cmd) 
00109 {
00110     std::string progName = _cmd.getProgramName();
00111     std::string xversion = _cmd.getVersion();
00112 
00113     std::cout << std::endl << progName << "  version: " 
00114               << xversion << std::endl << std::endl;
00115 }
00116 
00117 inline void StdOutput::usage(CmdLineInterface& _cmd ) 
00118 {
00119     std::cout << std::endl << "USAGE: " << std::endl << std::endl; 
00120 
00121     _shortUsage( _cmd, std::cout );
00122 
00123     std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl;
00124 
00125     _longUsage( _cmd, std::cout );
00126 
00127     std::cout << std::endl; 
00128 
00129 }
00130 
00131 inline void StdOutput::failure( CmdLineInterface& _cmd,
00132                                 ArgException& e ) 
00133 {
00134     std::string progName = _cmd.getProgramName();
00135 
00136     std::cerr << "PARSE ERROR: " << e.argId() << std::endl
00137               << "             " << e.error() << std::endl << std::endl;
00138 
00139     if ( _cmd.hasHelpAndVersion() )
00140         {
00141             std::cerr << "Brief USAGE: " << std::endl;
00142 
00143             _shortUsage( _cmd, std::cerr ); 
00144 
00145             std::cerr << std::endl << "For complete USAGE and HELP type: " 
00146                       << std::endl << "   " << progName << " --help" 
00147                       << std::endl << std::endl;
00148         }
00149     else
00150         usage(_cmd);
00151 
00152     throw ExitException(1);
00153 }
00154 
00155 inline void 
00156 StdOutput::_shortUsage( CmdLineInterface& _cmd, 
00157                         std::ostream& os ) const
00158 {
00159     std::list<Arg*> argList = _cmd.getArgList();
00160     std::string progName = _cmd.getProgramName();
00161     XorHandler xorHandler = _cmd.getXorHandler();
00162     std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
00163 
00164     std::string s = progName + " ";
00165 
00166     // first the xor
00167     for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
00168         {
00169             s += " {";
00170             for ( ArgVectorIterator it = xorList[i].begin(); 
00171                   it != xorList[i].end(); it++ )
00172                 s += (*it)->shortID() + "|";
00173 
00174             s[s.length()-1] = '}';
00175         }
00176 
00177     // then the rest
00178     for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
00179         if ( !xorHandler.contains( (*it) ) )
00180             s += " " + (*it)->shortID();
00181 
00182     // if the program name is too long, then adjust the second line offset 
00183     int secondLineOffset = static_cast<int>(progName.length()) + 2;
00184     if ( secondLineOffset > 75/2 )
00185         secondLineOffset = static_cast<int>(75/2);
00186 
00187     spacePrint( os, s, 75, 3, secondLineOffset );
00188 }
00189 
00190 inline void 
00191 StdOutput::_longUsage( CmdLineInterface& _cmd, 
00192                        std::ostream& os ) const
00193 {
00194     std::list<Arg*> argList = _cmd.getArgList();
00195     std::string message = _cmd.getMessage();
00196     XorHandler xorHandler = _cmd.getXorHandler();
00197     std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
00198 
00199     // first the xor 
00200     for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
00201         {
00202             for ( ArgVectorIterator it = xorList[i].begin(); 
00203                   it != xorList[i].end(); 
00204                   it++ )
00205                 {
00206                     spacePrint( os, (*it)->longID(), 75, 3, 3 );
00207                     spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
00208 
00209                     if ( it+1 != xorList[i].end() )
00210                         spacePrint(os, "-- OR --", 75, 9, 0);
00211                 }
00212             os << std::endl << std::endl;
00213         }
00214 
00215     // then the rest
00216     for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
00217         if ( !xorHandler.contains( (*it) ) )
00218             {
00219                 spacePrint( os, (*it)->longID(), 75, 3, 3 ); 
00220                 spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); 
00221                 os << std::endl;
00222             }
00223 
00224     os << std::endl;
00225 
00226     spacePrint( os, message, 75, 3, 0 );
00227 }
00228 
00229 inline void StdOutput::spacePrint( std::ostream& os, 
00230                                    const std::string& s, 
00231                                    int maxWidth, 
00232                                    int indentSpaces, 
00233                                    int secondLineOffset ) const
00234 {
00235     int len = static_cast<int>(s.length());
00236 
00237     if ( (len + indentSpaces > maxWidth) && maxWidth > 0 )
00238         {
00239             int allowedLen = maxWidth - indentSpaces;
00240             int start = 0;
00241             while ( start < len )
00242                 {
00243                     // find the substring length
00244                     // int stringLen = std::min<int>( len - start, allowedLen );
00245                     // doing it this way to support a VisualC++ 2005 bug 
00246                     using namespace std; 
00247                     int stringLen = min<int>( len - start, allowedLen );
00248 
00249                     // trim the length so it doesn't end in middle of a word
00250                     if ( stringLen == allowedLen )
00251                         while ( stringLen >= 0 &&
00252                                 s[stringLen+start] != ' ' && 
00253                                 s[stringLen+start] != ',' &&
00254                                 s[stringLen+start] != '|' ) 
00255                             stringLen--;
00256     
00257                     // ok, the word is longer than the line, so just split 
00258                     // wherever the line ends
00259                     if ( stringLen <= 0 )
00260                         stringLen = allowedLen;
00261 
00262                     // check for newlines
00263                     for ( int i = 0; i < stringLen; i++ )
00264                         if ( s[start+i] == '\n' )
00265                             stringLen = i+1;
00266 
00267                     // print the indent 
00268                     for ( int i = 0; i < indentSpaces; i++ )
00269                         os << " ";
00270 
00271                     if ( start == 0 )
00272                         {
00273                             // handle second line offsets
00274                             indentSpaces += secondLineOffset;
00275 
00276                             // adjust allowed len
00277                             allowedLen -= secondLineOffset;
00278                         }
00279 
00280                     os << s.substr(start,stringLen) << std::endl;
00281 
00282                     // so we don't start a line with a space
00283                     while ( s[stringLen+start] == ' ' && start < len )
00284                         start++;
00285             
00286                     start += stringLen;
00287                 }
00288         }
00289     else
00290         {
00291             for ( int i = 0; i < indentSpaces; i++ )
00292                 os << " ";
00293             os << s << std::endl;
00294         }
00295 }
00296 
00297 } //namespace TCLAP
00298 #endif