cmtkCommandLine.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2608 $
00026 //
00027 //  $LastChangedDate: 2010-12-07 14:39:57 -0800 (Tue, 07 Dec 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkCommandLine.h"
00034 
00035 #include <System/cmtkConsole.h>
00036 #include <System/cmtkExitException.h>
00037 
00038 #include <string.h>
00039 #include <sstream>
00040 
00041 namespace
00042 cmtk
00043 {
00044 
00047 
00048 CommandLine::CommandLine( const int properties ) 
00049   : ArgC( 0 ),
00050     ArgV( NULL )
00051 {
00052   this->SetDefaultInfo();    
00053   this->m_Properties = properties;
00054   
00055   this->BeginGroup( "MAIN", "Main Options" );
00056 }
00057 
00058 CommandLine::~CommandLine()
00059 {
00060   if ( this->Index < this->ArgC-1 )
00061     {
00062     StdErr << "WARNING: the following command line arguments were not used: \n";
00063     for ( size_t i = this->Index; i < this->ArgC; ++i )
00064       {
00065       StdErr << this->ArgV[i] << " ";
00066       }
00067     StdErr << "\n";
00068     }
00069 }
00070 
00071 void 
00072 CommandLine::SetDefaultInfo()
00073 {
00074   this->m_ProgramInfo[PRG_LCNSE] = "http://www.fsf.org/licensing/licenses/gpl.html";
00075   this->m_ProgramInfo[PRG_CNTRB] = "Torsten Rohlfing, Michael P. Hasak, Greg Jefferis, Calvin R. Maurer, Daniel B. Russakoff";
00076   this->m_ProgramInfo[PRG_ACKNL] = "CMTK is supported by the National Institute of Biomedical Imaging and BioEngineering under Grant EB008381";
00077   this->m_ProgramInfo[PRG_CATEG] = "CMTK.Miscellaneous";
00078   this->m_ProgramInfo[PRG_DOCUM] = "https://neuro.sri.com/cmtk/wiki/";
00079   this->m_ProgramInfo[PRG_VERSN] = CMTK_VERSION_STRING;
00080 }
00081 
00082 CommandLine::KeyActionGroupType::SmartPtr&
00083 CommandLine
00084 ::BeginGroup( const char* name, const char* description ) 
00085 { 
00086   this->m_KeyActionGroupList.push_back( KeyActionGroupType::SmartPtr( new KeyActionGroupType( name, description ) ) );
00087   this->m_KeyActionList = &(this->m_KeyActionGroupList.back()->m_KeyActionList);
00088   return this->m_KeyActionGroupList.back();
00089 }
00090 
00091 void
00092 CommandLine
00093 ::EndGroup() 
00094 {
00095   this->m_KeyActionList = &(this->m_KeyActionGroupList.front()->m_KeyActionList);
00096 }
00097 
00098 bool
00099 CommandLine::Parse( const int argc, const char* argv[] ) throw( ExitException, Self::Exception )
00100 {
00101   this->ArgC = argc;
00102   this->ArgV = argv;
00103 
00104   this->Index = 1;
00105   while ( (this->Index < this->ArgC) && (this->ArgV[this->Index][0] == '-') ) 
00106     {
00107     // Break at first non-switch argument.
00108     if ( this->ArgV[this->Index][0] != '-' ) return true;
00109     
00110     // Like POSIX, break at "--" terminator.
00111     if ( !strcmp( this->ArgV[this->Index], "--" ) ) 
00112       {
00113       ++this->Index;
00114       break;
00115       }
00116     
00117     bool found = false;
00118     if ( this->ArgV[this->Index][1] == '-' ) 
00119       {
00120       // long option
00121       for ( KeyActionListType::iterator it = this->m_KeyActionListComplete.begin(); !found && (it != this->m_KeyActionListComplete.end()); ++it )
00122         {
00123         found = (*it)->MatchAndExecute( std::string( this->ArgV[this->Index]+2 ), this->ArgC, this->ArgV, this->Index );
00124         }
00125       
00126       // not found?
00127       if ( !found ) 
00128         {
00129         // Check for "--xml" special option, which produces self description according to Slicer execution model.
00130         if ( !strcmp( this->ArgV[this->Index], "--xml" ) && !(this->m_Properties & PROPS_NOXML) ) 
00131           {
00132           this->WriteXML();
00133           throw ExitException( 0 );
00134           }
00135         
00136         // Check for "--help" special option, which produces textual description of all command line options
00137         if ( !strcmp( this->ArgV[this->Index], "--help" ) ) 
00138           {
00139           this->PrintHelp();
00140           throw ExitException( 0 );
00141           }
00142         
00143         // Check for "--wiki" special option, which produces Wiki-markup description of all command line options
00144         if ( !strcmp( this->ArgV[this->Index], "--wiki" ) ) 
00145           {
00146           this->PrintWiki();
00147           throw ExitException( 0 );
00148           }
00149         
00150         // Check for "--echo" special option, which echoes the command line to stderr. This does not exit the program automatically.
00151         if ( !strcmp( this->ArgV[this->Index], "--echo" ) ) 
00152           {
00153           for ( size_t i = 0; i < this->ArgC; ++i )
00154             {
00155             std::cerr << this->ArgV[i] << " ";
00156             }
00157           std::cerr << std::endl;
00158           found = true;
00159           }
00160         
00161         if ( ! found )
00162           throw( Exception( std::string("Unknown option: ") + std::string(this->ArgV[this->Index] ) ) );
00163         }
00164       } 
00165     else
00166       {
00167       const char* optChar = this->ArgV[this->Index]+1;
00168       while ( *optChar ) 
00169         {
00170         // short option
00171         for ( KeyActionListType::iterator it = this->m_KeyActionListComplete.begin(); !found && (it != this->m_KeyActionListComplete.end()); ++it )
00172           {
00173           found = (*it)->MatchAndExecute( *optChar, this->ArgC, this->ArgV, this->Index );
00174           }
00175       
00176         if ( !found ) 
00177           {
00178           const char opt[2] = { *optChar, 0 };
00179           throw( Exception( std::string("Unknown option: -") + std::string(opt) ) );
00180           }
00181         
00182         ++optChar; // next short option in this block, POSIX style.
00183         }
00184       }
00185     
00186     ++this->Index;
00187     } // while
00188 
00189   for ( NonOptionParameterListType::iterator it = this->m_NonOptionParameterList.begin(); it != this->m_NonOptionParameterList.end(); ++it, ++this->Index )
00190     {
00191     if ( this->Index >= this->ArgC )
00192       {     
00193       if ( ! ((*it)->m_Properties & PROPS_OPTIONAL) )
00194         throw( Exception( "Insufficient number of command line arguments", this->Index ) );
00195       }
00196     else
00197       {
00198       (*it)->Evaluate( this->ArgC, this->ArgV, this->Index );
00199       }
00200     }
00201   
00202   for ( NonOptionParameterVectorListType::iterator it = this->m_NonOptionParameterVectorList.begin(); it != this->m_NonOptionParameterVectorList.end(); ++it, ++this->Index )
00203     {
00204     if ( this->Index >= this->ArgC )
00205       {     
00206       if ( ! ((*it)->m_Properties & PROPS_OPTIONAL) )
00207         throw( Exception( "Insufficient number of command line arguments", this->Index ) );
00208       }
00209     else
00210       {
00211       (*it)->Evaluate( this->ArgC, this->ArgV, this->Index );
00212       }
00213     }
00214   
00215   return true;
00216 }
00217 
00218 void
00219 CommandLine::PrintHelp
00220 () const
00221 {
00222   const size_t lineWidth = StdErr.GetLineWidth();
00223 
00224   ProgramPropertiesMapType::const_iterator ppit = this->m_ProgramInfo.find(PRG_TITLE);
00225   if ( ppit != this->m_ProgramInfo.end() )
00226     {
00227     StdErr << "TITLE:\n\n";
00228     StdErr.FormatText( ppit->second, 5 ) << "\n";
00229     }
00230 
00231   ppit = this->m_ProgramInfo.find(PRG_DESCR);
00232   if ( ppit != this->m_ProgramInfo.end() )
00233     {
00234     StdErr << "\nDESCRIPTION:\n\n";
00235     StdErr.FormatText( ppit->second, 5 ) << "\n";
00236     }
00237 
00238   ppit = this->m_ProgramInfo.find(PRG_SYNTX);
00239   if ( ppit != this->m_ProgramInfo.end() )
00240     {
00241     StdErr << "\nSYNTAX:\n\n";
00242     StdErr.FormatText( ppit->second, 5 ) << "\n";
00243     }
00244   else
00245     {
00246     if ( this->m_NonOptionParameterList.size() || this->m_NonOptionParameterVectorList.size() )
00247       {
00248       StdErr << "\nSYNTAX:\n\n";
00249 
00250       std::ostringstream fmt;
00251       fmt << "[options] ";
00252       for ( NonOptionParameterListType::const_iterator it = this->m_NonOptionParameterList.begin(); it != this->m_NonOptionParameterList.end(); ++it )
00253         {
00254         fmt << (*it)->m_Name << " ";
00255         }
00256       for ( NonOptionParameterVectorListType::const_iterator it = this->m_NonOptionParameterVectorList.begin(); it != this->m_NonOptionParameterVectorList.end(); ++it )
00257         {
00258         fmt << (*it)->m_Name << " ";
00259         }
00260       StdErr.FormatText( fmt.str(), 5, lineWidth );
00261 
00262       StdErr << "\n  where\n";
00263 
00264       const int indent = 20;
00265       for ( NonOptionParameterListType::const_iterator it = this->m_NonOptionParameterList.begin(); it != this->m_NonOptionParameterList.end(); ++it )
00266         {
00267         fmt.str("");
00268 
00269         StdErr << "\n";
00270         fmt << (*it)->m_Name << " = ";
00271         if ( fmt.str().length() > static_cast<size_t>( indent-2 ) )
00272           fmt << "\n";
00273         else
00274           {
00275           while ( fmt.str().length() < static_cast<size_t>( indent ) )
00276             fmt << " ";
00277           }
00278         fmt << (*it)->m_Comment;
00279         StdErr.FormatText( fmt.str(), 5+indent, lineWidth, -indent ) << "\n";
00280         }
00281 
00282       for ( NonOptionParameterVectorListType::const_iterator it = this->m_NonOptionParameterVectorList.begin(); it != this->m_NonOptionParameterVectorList.end(); ++it )
00283         {
00284         fmt.str("");
00285         
00286         StdErr << "\n";
00287         fmt << (*it)->m_Name << " = ";
00288         if ( fmt.str().length() > static_cast<size_t>( indent-2 ) )
00289           fmt << "\n";
00290         else
00291           {
00292           while ( fmt.str().length() < static_cast<size_t>( indent ) )
00293             fmt << " ";
00294           }
00295         fmt << (*it)->m_Comment;
00296         StdErr.FormatText( fmt.str(), 5+indent, lineWidth, -indent ) << "\n";
00297         }
00298       }
00299     }
00300 
00301   StdErr << "\nLIST OF SUPPORTED OPTIONS:\n\n";
00302 
00303   for ( KeyActionGroupListType::const_iterator grp = this->m_KeyActionGroupList.begin(); grp != this->m_KeyActionGroupList.end(); ++grp )
00304     {
00305     const std::string& name = (*grp)->m_Name;
00306 
00307     size_t indent = 0;
00308     if ( name != "MAIN" )
00309       {
00310       StdErr << (*grp)->m_Description << "\n\n";
00311       indent = 2;
00312       }
00313 
00314     const KeyActionListType& kal = (*grp)->m_KeyActionList;
00315     for ( KeyActionListType::const_iterator it = kal.begin(); it != kal.end(); ++it )
00316       {
00317       (*it)->PrintHelp( indent );
00318       }
00319     }
00320   
00321   StdErr << "\n";
00322 }
00323 
00324 void
00325 CommandLine::PrintWiki
00326 () const
00327 {
00328   ProgramPropertiesMapType::const_iterator ppit = this->m_ProgramInfo.find(PRG_TITLE);
00329   if ( ppit != this->m_ProgramInfo.end() )
00330     {
00331     StdOut << "== Title ==\n\n";
00332     StdOut << ppit->second << "\n\n";
00333     }
00334 
00335   ppit = this->m_ProgramInfo.find(PRG_DESCR);
00336   if ( ppit != this->m_ProgramInfo.end() )
00337     {
00338     StdOut << "== Description ==\n\n";
00339     StdOut << ppit->second << "\n\n";
00340     }
00341   
00342   ppit = this->m_ProgramInfo.find(PRG_SYNTX);
00343   if ( ppit != this->m_ProgramInfo.end() )
00344     {
00345     StdOut << "== Syntax ==\n\n";
00346     StdOut << ppit->second << "\n\n";
00347     }
00348   else
00349     {
00350     if ( this->m_NonOptionParameterList.size() || this->m_NonOptionParameterVectorList.size() )
00351       {
00352       StdOut << "== Syntax ==\n\n";
00353       
00354       StdOut << ": <tt>[options] ";
00355       for ( NonOptionParameterListType::const_iterator it = this->m_NonOptionParameterList.begin(); it != this->m_NonOptionParameterList.end(); ++it )
00356         {
00357         StdOut << (*it)->m_Name << " ";
00358         }
00359       for ( NonOptionParameterVectorListType::const_iterator it = this->m_NonOptionParameterVectorList.begin(); it != this->m_NonOptionParameterVectorList.end(); ++it )
00360         {
00361         StdOut << (*it)->m_Name << " ";
00362         }
00363       StdOut << "</tt>\n\nwhere\n";
00364 
00365       for ( NonOptionParameterListType::const_iterator it = this->m_NonOptionParameterList.begin(); it != this->m_NonOptionParameterList.end(); ++it )
00366         {
00367         StdOut << "\n";
00368         StdOut << "; <tt>" << (*it)->m_Name << "</tt> : ";
00369         StdOut << (*it)->m_Comment << "\n";;
00370         }
00371       for ( NonOptionParameterVectorListType::const_iterator it = this->m_NonOptionParameterVectorList.begin(); it != this->m_NonOptionParameterVectorList.end(); ++it )
00372         {
00373         StdOut << "\n";
00374         StdOut << "; <tt>" << (*it)->m_Name << "</tt> : ";
00375         StdOut << (*it)->m_Comment << "\n";;
00376         }
00377       }
00378     }
00379   
00380   StdOut << "\n== List of Supported Options ==\n\n";
00381 
00382   for ( KeyActionGroupListType::const_iterator grp = this->m_KeyActionGroupList.begin(); grp != this->m_KeyActionGroupList.end(); ++grp )
00383     {
00384     const std::string& name = (*grp)->m_Name;
00385     if ( name != "MAIN" )
00386       {
00387       StdOut << "=== " << (*grp)->m_Description << " ===\n\n";
00388       }
00389 
00390     const KeyActionListType& kal = (*grp)->m_KeyActionList;
00391     for ( KeyActionListType::const_iterator it = kal.begin(); it != kal.end(); ++it )
00392       {
00393       (*it)->PrintWikiWithPrefix();
00394       StdOut << "\n";
00395       }
00396     }
00397   
00398   StdOut << "\n";
00399 }
00400 
00401 Console& operator<<( Console& console, CommandLine::Exception e )
00402 {
00403   console << e.Message << " [argument #" << e.Index << "]\n";
00404   return console;
00405 }
00406 
00407 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines