BASIS  r3148
CmdLine.cxx
Go to the documentation of this file.
00001 /**
00002  * @file  CmdLine.cxx
00003  * @brief Manages command line definition and parsing of arguments.
00004  *
00005  * Copyright (c) 2011 University of Pennsylvania. All rights reserved.<br />
00006  * See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00007  *
00008  * Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00009  */
00010 
00011 
00012 #include <set>
00013 
00014 
00015 #include <basis/tclap/Arg.h>
00016 #include <basis/tclap/ArgException.h>
00017 #include <basis/tclap/StdOutput.h>
00018 #include <basis/tclap/Visitor.h>
00019 #include <basis/tclap/VersionVisitor.h>
00020 #include <basis/tclap/XorHandler.h>
00021 
00022 #include <basis/os.h>     // exename()
00023 #include <basis/except.h> // BASIS_THROW, runtime_error
00024 #include <basis/stdio.h>  // get_terminal_columns(), print_wrapped()
00025 
00026 #include <basis/CmdLine.h>
00027 
00028 
00029 // acceptable in .cxx file
00030 using namespace std;
00031 
00032 
00033 namespace basis {
00034 
00035 
00036 // ===========================================================================
00037 // class: StdOutput
00038 // ===========================================================================
00039 
00040 /**
00041  * @brief Prints help, version information, and command-line errors.
00042  */
00043 class StdOutput : public TCLAP::CmdLineOutput
00044 {
00045     // -----------------------------------------------------------------------
00046     // construction / destruction
00047 public:
00048 
00049     /**
00050      * @brief Constructor.
00051      *
00052      * @param [in] cmd The command-line with additional attributes
00053      *                 for which the output is generated.
00054      */
00055     StdOutput(CmdLine* cmd);
00056 
00057     // -----------------------------------------------------------------------
00058     // interface functions
00059 public:
00060 
00061     /**
00062      * @brief Prints a short help, i.e., usage information.
00063      */
00064     virtual void usage(TCLAP::CmdLineInterface&);
00065 
00066     /**
00067      * @brief Prints the full help.
00068      */
00069     virtual void help(TCLAP::CmdLineInterface&);
00070 
00071     /**
00072      * @brief Prints the version information.
00073      */
00074     virtual void version(TCLAP::CmdLineInterface&);
00075 
00076     /**
00077      * @brief Prints an error message.
00078      *
00079      * @param [in] e The exception that caused the failure.
00080      */
00081     virtual void failure(TCLAP::CmdLineInterface&, TCLAP::ArgException& e);
00082 
00083     /**
00084      * @brief Get corresponding command-line object.
00085      *
00086      * @returns Command-line with additional attributes for which the
00087      *          output is generated.
00088      */
00089     CmdLine* getCmdLine() { return _cmd; }
00090 
00091     // -----------------------------------------------------------------------
00092     // helpers
00093 protected:
00094 
00095     /**
00096      * @brief Update information about terminal size.
00097      */
00098     void updateTerminalInfo();
00099 
00100     /**
00101      * @brief Determine whether an argument has a label or not.
00102      *
00103      * @param [in] arg Command-line argument.
00104      *
00105      * @returns Whether the given argument is a positional argument.
00106      */
00107     bool isUnlabeledArg(TCLAP::Arg* arg) const;
00108 
00109     /**
00110      * @brief Get string describing type of argument value.
00111      *
00112      * @param [in] arg Command-line argument.
00113      *
00114      * @returns String describing type of argument value.
00115      */
00116     string getTypeDescription(TCLAP::Arg* arg) const;
00117 
00118     /**
00119      * @brief Get argument usage string.
00120      *
00121      * @param [in] arg Command-line argument.
00122      * @param [in] all Whether to include also optional short flags.
00123      *
00124      * @returns Short argument description.
00125      */
00126     string getArgumentID(TCLAP::Arg* arg, bool all = false) const;
00127 
00128     /**
00129      * @brief Prints help of command-line argument.
00130      *
00131      * @param [in] os              Output stream.
00132      * @param [in] arg             Command-line argument.
00133      * @param [in] indentFirstLine Whether first line should be indented.
00134      */
00135     void printArgumentHelp(ostream& os, TCLAP::Arg* arg, bool indentFirstLine = true) const;
00136 
00137     /**
00138      * Prints usage information, i.e., synopsis.
00139      *
00140      * @param [in] os      Output stream.
00141      * @param [in] heading Enable/disable output of section heading.
00142      */
00143     void printUsage(ostream& os, bool heading = true) const;
00144 
00145     /**
00146      * @brief Prints program description.
00147      *
00148      * @param [in] os Output stream.
00149      */
00150     void printDescription(ostream& os) const;
00151 
00152     /**
00153      * @brief Prints command-line arguments.
00154      *
00155      * @param [in] os  Output stream.
00156      * @param [in] all Enable/disable help output of all arguments or only
00157      *                 the more important arguments.
00158      */
00159     void printArguments(ostream& os, bool all) const;
00160 
00161     /**
00162      * @brief Print example usage.
00163      *
00164      * @param [in] os Output stream.
00165      */
00166     void printExample(ostream& os) const;
00167 
00168     /**
00169      * @brief Print contact information.
00170      *
00171      * @param [in] os Output stream.
00172      */
00173     void printContact(ostream& os) const;
00174 
00175     // -----------------------------------------------------------------------
00176     // member variables
00177 protected:
00178 
00179     CmdLine*    _cmd;     ///< The command-line with additional attributes.
00180     set<string> _stdargs; ///< Names of standard arguments.
00181     int         _columns; ///< Maximum number of columns to use for output.
00182 
00183 }; // class StdOutput
00184 
00185 // ---------------------------------------------------------------------------
00186 // construction
00187 // ---------------------------------------------------------------------------
00188 
00189 // ---------------------------------------------------------------------------
00190 StdOutput::StdOutput(CmdLine* cmd)
00191 :
00192     _cmd(cmd),
00193     _columns(75)
00194 {
00195     _stdargs.insert("ignore_rest");
00196     _stdargs.insert("verbose");
00197     _stdargs.insert("help");
00198     _stdargs.insert("helpshort");
00199     _stdargs.insert("helpxml");
00200     _stdargs.insert("helpman");
00201     _stdargs.insert("version");
00202 }
00203 
00204 // ---------------------------------------------------------------------------
00205 // interface functions
00206 // ---------------------------------------------------------------------------
00207 
00208 // ---------------------------------------------------------------------------
00209 void StdOutput::usage(TCLAP::CmdLineInterface&)
00210 {
00211     updateTerminalInfo();
00212     cout << endl;
00213     printUsage(cout, false);
00214     //printArguments(cout, false);
00215     cout << endl;
00216 }
00217 
00218 // ---------------------------------------------------------------------------
00219 void StdOutput::help(TCLAP::CmdLineInterface&)
00220 {
00221     updateTerminalInfo();
00222     cout << endl;
00223     printUsage(cout);
00224     printDescription(cout);
00225     printArguments(cout, true);
00226     printExample(cout);
00227     printContact(cout);
00228     cout << endl;
00229 }
00230 
00231 // ---------------------------------------------------------------------------
00232 void StdOutput::version(TCLAP::CmdLineInterface&)
00233 {
00234     std::string name      = _cmd->getProgramName();
00235     std::string project   = _cmd->getProjectName();
00236     std::string version   = _cmd->getVersion();
00237     std::string copyright = _cmd->getCopyright();
00238     std::string license   = _cmd->getLicense();
00239 
00240     // print version information
00241     cout << name;
00242     if (!project.empty()) cout << " (" << project << ")";
00243     cout << " " << version;
00244     cout << endl;
00245     // print copyright and license information
00246     if (!copyright.empty()) {
00247         cout << "Copyright (c) " << copyright << ". All rights reserved." << endl;
00248     }
00249     if (!license.empty()) cout << license << endl;
00250 }
00251 
00252 // ---------------------------------------------------------------------------
00253 void StdOutput::failure(TCLAP::CmdLineInterface&, TCLAP::ArgException& e)
00254 {
00255     if (!e.argId().empty() && e.argId() != " ") cerr << e.argId() << ", ";
00256     cerr << e.error() << endl;
00257     cerr << "See --help for a list of available and required arguments." << endl;
00258     throw TCLAP::ExitException(1);
00259 }
00260 
00261 // ---------------------------------------------------------------------------
00262 // helpers
00263 // ---------------------------------------------------------------------------
00264 
00265 // ---------------------------------------------------------------------------
00266 inline void StdOutput::updateTerminalInfo()
00267 {
00268     // get maximum number of columns
00269     int columns = get_terminal_columns();
00270     // update member variable, but maintain minimum number of columns
00271     if (columns > 40) _columns = columns;
00272 }
00273 
00274 // ---------------------------------------------------------------------------
00275 inline bool StdOutput::isUnlabeledArg(TCLAP::Arg* arg) const
00276 {
00277     const string id = arg->longID();
00278     string::size_type pos = id.find(TCLAP::Arg::nameStartString() + arg->getName());
00279     return pos == string::npos;
00280 }
00281 
00282 // ---------------------------------------------------------------------------
00283 inline string StdOutput::getTypeDescription(TCLAP::Arg* arg) const
00284 {
00285     string typedesc = arg->shortID();
00286     string::size_type start = typedesc.find ('<');
00287     string::size_type end   = typedesc.rfind('>');
00288     if (start != string::npos && end != string::npos) {
00289         return typedesc.substr(start + 1, end - start - 1);
00290     } else {
00291         return "";
00292     }
00293 }
00294 
00295 // ---------------------------------------------------------------------------
00296 inline string StdOutput::getArgumentID(TCLAP::Arg* arg, bool all) const
00297 {
00298     string id;
00299     const bool option = !isUnlabeledArg(arg);
00300     if (option) {
00301         if (all && arg->getFlag() != "") {
00302             id += TCLAP::Arg::flagStartString() + arg->getFlag();
00303             id += "  ";
00304         }
00305         id += TCLAP::Arg::nameStartString() + arg->getName();
00306     }
00307     if (arg->isValueRequired()) {
00308         if (option) id += TCLAP::Arg::delimiter();
00309         id += getTypeDescription(arg);
00310     }
00311     return id;
00312 }
00313 
00314 // ---------------------------------------------------------------------------
00315 inline
00316 void StdOutput::printArgumentHelp(ostream& os, TCLAP::Arg* arg, bool indentFirstLine) const
00317 {
00318     string id   = getArgumentID(arg, true);
00319     string desc = arg->getDescription();
00320     if (desc.compare (0, 12, "(required)  ")    == 0) desc.erase(0, 12);
00321     if (desc.compare (0, 15, "(OR required)  ") == 0) desc.erase(0, 15);
00322     if (indentFirstLine) print_wrapped(os, id, _columns, 8, 0);
00323     else                 print_wrapped(os, id, _columns, 0, 8);
00324     if (!desc.empty()) {
00325         print_wrapped(os, desc, _columns, 15, 0);
00326     }
00327 }
00328 
00329 // ---------------------------------------------------------------------------
00330 void StdOutput::printUsage(ostream& os, bool heading) const
00331 {
00332     string                        exec_name  = os::exename();
00333     list<TCLAP::Arg*>             args       = _cmd->getArgList();
00334     TCLAP::XorHandler&            xorhandler = _cmd->getXorHandler();
00335     vector< vector<TCLAP::Arg*> > xors       = xorhandler.getXorList();
00336 
00337     // separate into argument groups
00338     vector< vector<TCLAP::Arg*> > reqxors;
00339     vector< vector<TCLAP::Arg*> > optxors;
00340     for (int i = 0; static_cast<unsigned int>(i) < xors.size(); i++) {
00341         if (xors[i].size() > 0) {
00342             if (xors[i][0]->isRequired()) reqxors.push_back(xors[i]);
00343             else                          optxors.push_back(xors[i]);
00344         }
00345     }
00346     list<TCLAP::Arg*> reqargs, reqposargs;
00347     list<TCLAP::Arg*> optargs, optposargs;
00348     for (TCLAP::ArgListIterator it = args.begin(); it != args.end(); it++) {
00349         if (_stdargs.find((*it)->getName()) == _stdargs.end()
00350                 && !xorhandler.contains((*it))) {
00351             if (isUnlabeledArg(*it)) {
00352                 if ((*it)->isRequired()) {
00353                     (*it)->addToList(reqposargs);
00354                 } else {
00355                     (*it)->addToList(optposargs);
00356                 }
00357             } else {
00358                 if ((*it)->isRequired()) {
00359                     (*it)->addToList(reqargs);
00360                 } else {
00361                     (*it)->addToList(optargs);
00362                 }
00363             }
00364         }
00365     }
00366 
00367     // executable name
00368     string s = exec_name;
00369     string id;
00370     // optional arguments with flags
00371     for (int i = 0; static_cast<unsigned int>(i) < optxors.size(); i++) {
00372         s += " [";
00373         for (TCLAP::ArgVectorIterator it = optxors[i].begin();
00374                 it != optxors[i].end(); it++) {
00375             id = getArgumentID(*it);
00376             s += id;
00377             if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00378                 s += "...";
00379             }
00380             s += "|";
00381         }
00382         s[s.length() - 1] = ']';
00383     }
00384     for (TCLAP::ArgListIterator it = optargs.begin(); it != optargs.end(); it++) {
00385         id = getArgumentID(*it);
00386         s += " [";
00387         s += id;
00388         s += "]";
00389         if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00390             s += "...";
00391         }
00392     }
00393     // required arguments with flags
00394     for (int i = 0; static_cast<unsigned int>(i) < reqxors.size(); i++) {
00395         s += " (";
00396         for (TCLAP::ArgVectorIterator it = reqxors[i].begin();
00397                 it != reqxors[i].end(); it++) {
00398             id = getArgumentID(*it);
00399             s += id;
00400             if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00401                 s += "...";
00402             }
00403             s += "|";
00404         }
00405         s[s.length() - 1] = ')';
00406     }
00407     for (TCLAP::ArgListIterator it = reqargs.begin(); it != reqargs.end(); it++) {
00408         id = getArgumentID(*it);
00409         s += " ";
00410         s += id;
00411         if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00412             s += "...";
00413         }
00414     }
00415     // required positional arguments
00416     for (TCLAP::ArgListIterator it = reqposargs.begin(); it != reqposargs.end(); it++) {
00417         id = getArgumentID(*it);
00418         s += " ";
00419         s += id;
00420         if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00421             s += "...";
00422         }
00423     }
00424     // optional positional arguments
00425     for (TCLAP::ArgListIterator it = optposargs.begin(); it != optposargs.end(); it++) {
00426         id = getArgumentID(*it);
00427         s += " [";
00428         s += id;
00429         s += "]";
00430         if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00431             s += "...";
00432         }
00433     }
00434 
00435     // print usage with proper number of columns
00436     // if the program name is too long, then adjust the second line offset 
00437     if (heading) {
00438         os << "SYNOPSIS" << endl;
00439     }
00440     int offset = static_cast<int>(exec_name.length()) + 1;
00441     if (offset > _columns / 2) offset = 8;
00442     print_wrapped(os, s, _columns, 4, offset);
00443     print_wrapped(os, exec_name + " [-h|--help|--helpshort|--helpxml|--helpman|--version]", _columns, 4, offset);
00444 }
00445 
00446 // ---------------------------------------------------------------------------
00447 void StdOutput::printDescription(ostream& os) const
00448 {
00449     if (_cmd->getMessage() != "") {
00450         os << endl;
00451         os << "DESCRIPTION" << endl;
00452         print_wrapped(os, _cmd->getMessage(), _columns, 4, 0);
00453     }
00454 }
00455 
00456 // ---------------------------------------------------------------------------
00457 void StdOutput::printArguments(ostream& os, bool all) const
00458 {
00459     list<TCLAP::Arg*>             args       = _cmd->getArgList();
00460     TCLAP::XorHandler&            xorhandler = _cmd->getXorHandler();
00461     vector< vector<TCLAP::Arg*> > xors       = xorhandler.getXorList();
00462 
00463     // separate into argument groups
00464     vector< vector<TCLAP::Arg*> > reqxors;
00465     vector< vector<TCLAP::Arg*> > optxors;
00466     for (int i = 0; static_cast<unsigned int>(i) < xors.size(); i++) {
00467         if (xors[i].size() > 0) {
00468             if (xors[i][0]->isRequired()) reqxors.push_back(xors[i]);
00469             else                          optxors.push_back(xors[i]);
00470         }
00471     }
00472     list<TCLAP::Arg*> reqargs, reqposargs;
00473     list<TCLAP::Arg*> optargs, optposargs;
00474     list<TCLAP::Arg*> stdargs;
00475     for (TCLAP::ArgListIterator it = args.begin(); it != args.end(); it++) {
00476         if (_stdargs.find((*it)->getName()) != _stdargs.end()) {
00477             (*it)->addToList(stdargs);
00478         } else if (!xorhandler.contains((*it))) {
00479             if (isUnlabeledArg(*it)) {
00480                 if ((*it)->isRequired()) {
00481                     (*it)->addToList(reqposargs);
00482                 } else {
00483                     (*it)->addToList(optposargs);
00484                 }
00485             } else {
00486                 if ((*it)->isRequired()) {
00487                     (*it)->addToList(reqargs);
00488                 } else {
00489                     (*it)->addToList(optargs);
00490                 }
00491             }
00492         }
00493     }
00494 
00495     // return if command has no arguments
00496     if (xors.empty() && reqargs.empty() && optargs.empty()) {
00497         return;
00498     }
00499 
00500     os << endl;
00501     os << "OPTIONS" << endl;
00502 
00503     // required arguments
00504     if (!reqxors.empty() || !reqargs.empty() || !reqposargs.empty()) {
00505         os << "    Required arguments:" << endl;
00506         for (TCLAP::ArgListIterator it = reqposargs.begin(); it != reqposargs.end(); it++) {
00507             if (it != reqposargs.begin()) os << endl;
00508             printArgumentHelp(os, *it);
00509         }
00510         for (int i = 0; static_cast<unsigned int>(i) < reqxors.size(); i++) {
00511             if (i > 0 || !reqposargs.empty()) os << endl;
00512             for (TCLAP::ArgVectorIterator it = reqxors[i].begin();
00513                     it != reqxors[i].end(); it++) {
00514                 if (it != reqxors[i].begin()) {
00515                     os << "     or ";
00516                     printArgumentHelp(os, *it, false);
00517                 } else {
00518                     printArgumentHelp(os, *it);
00519                 }
00520             }
00521         }
00522         for (TCLAP::ArgListIterator it = reqargs.begin(); it != reqargs.end(); it++) {
00523             if (!reqxors.empty() || it != reqargs.begin()) os << endl;
00524             printArgumentHelp(os, *it);
00525         }
00526     }
00527 
00528     // optional arguments
00529     if (!optxors.empty() || !optargs.empty()) {
00530         if (!reqxors.empty() || !reqargs.empty() || !reqposargs.empty()) {
00531             os << endl;
00532         }
00533         os << "    Optional arguments:" << endl;
00534         for (TCLAP::ArgListIterator it = optposargs.begin(); it != optposargs.end(); it++) {
00535             if (it != optposargs.begin()) os << endl;
00536             printArgumentHelp(os, *it);
00537         }
00538         for (int i = 0; static_cast<unsigned int>(i) < optxors.size(); i++) {
00539             if (i > 0 || !optposargs.empty()) os << endl;
00540             for (TCLAP::ArgVectorIterator it = optxors[i].begin();
00541                     it != optxors[i].end(); it++) {
00542                 if (it != optxors[i].begin()) {
00543                     os << "     or ";
00544                     printArgumentHelp(os, *it, false);
00545                 } else {
00546                     printArgumentHelp(os, *it);
00547                 }
00548             }
00549         }
00550         for (TCLAP::ArgListIterator it = optargs.begin(); it != optargs.end(); it++) {
00551             if (!optxors.empty() || it != optargs.begin()) os << endl;
00552             printArgumentHelp(os, *it);
00553         }
00554     }
00555 
00556     // standard arguments
00557     if (all && !stdargs.empty()) {
00558         if (!xors.empty() || !reqargs.empty() || !optargs.empty()) {
00559             os << endl;
00560         }
00561         os << "    Standard arguments:" << endl;
00562         for (TCLAP::ArgListIterator it = stdargs.begin(); it != stdargs.end(); it++) {
00563             if (it != stdargs.begin()) os << endl;
00564             printArgumentHelp(os, *it);
00565         }
00566     }
00567 }
00568 
00569 // ---------------------------------------------------------------------------
00570 void StdOutput::printExample(ostream& os) const
00571 {
00572     const string exec_name = os::exename();
00573     const vector<string>& examples = _cmd->getExamples();
00574 
00575     if (!examples.empty()) {
00576         os << endl;
00577         os << "EXAMPLE" << endl;
00578         for (vector<string>::const_iterator it = examples.begin();
00579                 it != examples.end(); ++it) {
00580             if (it != examples.begin()) os << endl;
00581             string example = *it;
00582             string::size_type pos;
00583             // backwards compatibility
00584             pos = 0;
00585             while ((pos = example.find("EXECNAME", pos)) != string::npos) {
00586                 example.replace(pos, 8, exec_name);
00587             }
00588             // desired placeholder as it relates to the exename() function
00589             pos = 0;
00590             while ((pos = example.find("EXENAME", pos)) != string::npos) {
00591                 example.replace(pos, 7, exec_name);
00592             }
00593             print_wrapped(os, example, _columns, 4, 4);
00594         }
00595     }
00596 }
00597 
00598 // ---------------------------------------------------------------------------
00599 void StdOutput::printContact(ostream& os) const
00600 {
00601     if (_cmd->getContact() != "") {
00602         os << endl;
00603         os << "CONTACT" << endl;
00604         print_wrapped(os, _cmd->getContact(), _columns, 4, 0);
00605     }
00606 }
00607 
00608 // ===========================================================================
00609 // class: HelpVisitor
00610 // ===========================================================================
00611 
00612 /**
00613  * @brief Displays either full help or usage only.
00614  */
00615 class HelpVisitor: public TCLAP::Visitor
00616 {
00617     // -----------------------------------------------------------------------
00618     // construction / destruction
00619 public:
00620 
00621     /**
00622      * @brief Constructor.
00623      *
00624      * @param [in] out The object which handles the output.
00625      * @param [in] all Enable/disable full help output.
00626      */
00627     HelpVisitor(StdOutput* out, bool all = true)
00628     :
00629         Visitor(),
00630         _out(out),
00631         _all(all)
00632     { }
00633 
00634     // -----------------------------------------------------------------------
00635     // interface function
00636 public:
00637 
00638     /**
00639      * @brief Print help.
00640      */
00641     void visit()
00642     {
00643         if (_all) _out->help (*(_out->getCmdLine()));
00644         else      _out->usage(*(_out->getCmdLine()));
00645         // exit
00646         throw TCLAP::ExitException(0); 
00647     }
00648 
00649     // -----------------------------------------------------------------------
00650     // member variables
00651 protected:
00652 
00653     StdOutput* _out; ///< Object handling the output.
00654     bool       _all; ///< Enable/disable full help output.
00655 
00656     // -----------------------------------------------------------------------
00657     // unsupported
00658 private:
00659 
00660     HelpVisitor(const HelpVisitor&);            ///< Not implemented.
00661     HelpVisitor& operator=(const HelpVisitor&); ///< Not implemented.
00662 
00663 }; // class HelpVisitor
00664 
00665 // ===========================================================================
00666 // class: XmlVisitor
00667 // ===========================================================================
00668 
00669 /**
00670  * @brief Outputs the command-line interface in XML format.
00671  */
00672 class XmlVisitor: public TCLAP::Visitor
00673 {
00674     // -----------------------------------------------------------------------
00675     // construction / destruction
00676 public:
00677 
00678     /**
00679      * @brief Constructor.
00680      */
00681     XmlVisitor()
00682     :
00683         Visitor()
00684     { }
00685 
00686     // -----------------------------------------------------------------------
00687     // interface function
00688 public:
00689 
00690     /**
00691      * @brief Print help.
00692      */
00693     void visit()
00694     {
00695         cerr << "Not implemented yet! Use --help instead." << endl;
00696         // exit
00697         throw TCLAP::ExitException(0); 
00698     }
00699 
00700     // -----------------------------------------------------------------------
00701     // member variables
00702 protected:
00703 
00704 
00705     // -----------------------------------------------------------------------
00706     // unsupported
00707 private:
00708 
00709     XmlVisitor(const XmlVisitor&);            ///< Not implemented.
00710     XmlVisitor& operator=(const XmlVisitor&); ///< Not implemented.
00711 
00712 }; // class XmlVisitor
00713 
00714 // ===========================================================================
00715 // class: ManPageVisitor
00716 // ===========================================================================
00717 
00718 /**
00719  * @brief Displays man page and exits.
00720  */
00721 class ManPageVisitor: public TCLAP::Visitor
00722 {
00723     // -----------------------------------------------------------------------
00724     // construction / destruction
00725 public:
00726 
00727     /**
00728      * @brief Constructor.
00729      */
00730     ManPageVisitor()
00731     :
00732         Visitor()
00733     { }
00734 
00735     // -----------------------------------------------------------------------
00736     // interface function
00737 public:
00738 
00739     /**
00740      * @brief Print help.
00741      */
00742     void visit()
00743     {
00744         cerr << "Not implemented yet! Use --help instead." << endl;
00745         // exit
00746         throw TCLAP::ExitException(0);
00747     }
00748 
00749     // -----------------------------------------------------------------------
00750     // member variables
00751 protected:
00752 
00753 
00754     // -----------------------------------------------------------------------
00755     // unsupported
00756 private:
00757 
00758     ManPageVisitor(const ManPageVisitor&);            ///< Not implemented.
00759     ManPageVisitor& operator=(const ManPageVisitor&); ///< Not implemented.
00760 
00761 }; // class ManPageVisitor
00762 
00763 // ===========================================================================
00764 // class: CmdLine
00765 // ===========================================================================
00766 
00767 // ---------------------------------------------------------------------------
00768 CmdLine::CmdLine(const std::string& name,
00769                  const std::string& project,
00770                  const std::string& description,
00771                  const std::string& example,
00772                  const std::string& version,
00773                  const std::string& copyright,
00774                  const std::string& license,
00775                  const std::string& contact,
00776                  bool               stdargs)
00777 :
00778     TCLAP::CmdLine(description, ' ', version, false),
00779     _xorHandler(XorHandler()),
00780     _name(name),
00781     _project(project),
00782     _copyright(copyright),
00783     _license(license),
00784     _contact(contact)
00785 {
00786     if (example != "") _examples.push_back(example);
00787     setup(stdargs);
00788 }
00789 
00790 // ---------------------------------------------------------------------------
00791 CmdLine::CmdLine(const std::string&              name,
00792                  const std::string&              project,
00793                  const std::string&              description,
00794                  const std::vector<std::string>& examples,
00795                  const std::string&              version,
00796                  const std::string&              copyright,
00797                  const std::string&              license,
00798                  const std::string&              contact,
00799                  bool                            stdargs)
00800 :
00801     TCLAP::CmdLine(description, ' ', version, false),
00802     _xorHandler(XorHandler()),
00803     _name(name),
00804     _project(project),
00805     _examples(examples),
00806     _copyright(copyright),
00807     _license(license),
00808     _contact(contact)
00809 {
00810     setup(stdargs);
00811 }
00812 
00813 // ---------------------------------------------------------------------------
00814 void CmdLine::setup(bool stdargs)
00815 {
00816     // replace output handler
00817     StdOutput* output = new StdOutput(this);
00818     if (_output) delete _output;
00819     _output = output;
00820 
00821     // remove arguments added by TCLAP::CmdLine (ignore)
00822     ClearContainer(_argDeleteOnExitList);
00823     ClearContainer(_visitorDeleteOnExitList);
00824     TCLAP::CmdLine::_argList.clear();
00825 
00826     // add standard arguments
00827     TCLAP::Visitor* v;
00828 
00829     v = new TCLAP::IgnoreRestVisitor();
00830     SwitchArg* ignore  = new SwitchArg(
00831               TCLAP::Arg::flagStartString(), TCLAP::Arg::ignoreNameString(),
00832               "Ignores the rest of the labeled arguments.",
00833               false, v);
00834     add(ignore);
00835     deleteOnExit(ignore);
00836     deleteOnExit(v);
00837 
00838     if (stdargs) {
00839         v = new HelpVisitor(output, true);
00840         TCLAP::SwitchArg* help = new TCLAP::SwitchArg(
00841                 "h", "help", "Display help and exit.", false, v);
00842         add(help);
00843         deleteOnExit(help);
00844         deleteOnExit(v);
00845 
00846         v = new HelpVisitor(output, false);
00847         TCLAP::SwitchArg* helpshort = new TCLAP::SwitchArg(
00848                 "", "helpshort", "Display short help and exit.", false, v);
00849         add(helpshort);
00850         deleteOnExit(helpshort);
00851         deleteOnExit(v);
00852 
00853         v = new XmlVisitor();
00854         TCLAP::SwitchArg* helpxml = new TCLAP::SwitchArg(
00855                 "", "helpxml", "Display help in XML format and exit.", false, v);
00856         add(helpxml);
00857         deleteOnExit(helpxml);
00858         deleteOnExit(v);
00859 
00860         v = new ManPageVisitor();
00861         TCLAP::SwitchArg* helpman = new TCLAP::SwitchArg(
00862                 "", "helpman", "Display help as man page and exit.", false, v);
00863         add(helpman);
00864         deleteOnExit(helpman);
00865         deleteOnExit(v);
00866 
00867         v = new TCLAP::VersionVisitor(this, &_output);
00868         TCLAP::SwitchArg* vers = new TCLAP::SwitchArg(
00869                 "", "version", "Display version information and exit.", false, v);
00870         add(vers);
00871         deleteOnExit(vers);
00872         deleteOnExit(v);
00873     }
00874 }
00875 
00876 // -----------------------------------------------------------------------
00877 void CmdLine::add(Arg& a)
00878 {
00879     TCLAP::CmdLine::add(a);
00880 }
00881 
00882 // -----------------------------------------------------------------------
00883 void CmdLine::add(Arg* a)
00884 {
00885     TCLAP::CmdLine::add(a);
00886 }
00887 
00888 // -----------------------------------------------------------------------
00889 void CmdLine::xorAdd(Arg& a, Arg& b)
00890 {
00891     vector<TCLAP::Arg*> xors;
00892     xors.push_back(&a);
00893     xors.push_back(&b);
00894     xorAdd(xors);
00895 }
00896 
00897 // -----------------------------------------------------------------------
00898 void CmdLine::print_usage() const
00899 {
00900     _output->usage(*const_cast<CmdLine*>(this));
00901 }
00902 
00903 // -----------------------------------------------------------------------
00904 void CmdLine::print_help() const
00905 {
00906     StdOutput* output = dynamic_cast<StdOutput*>(_output);
00907     if (output) output ->help (*const_cast<CmdLine*>(this));
00908     else        _output->usage(*const_cast<CmdLine*>(this));
00909 }
00910 
00911 // -----------------------------------------------------------------------
00912 void CmdLine::print_version() const
00913 {
00914     _output->version(*const_cast<CmdLine*>(this));
00915 }
00916 
00917 // -----------------------------------------------------------------------
00918 void CmdLine::xorAdd(vector<Arg*>& xors)
00919 {
00920     _xorHandler.add(xors);
00921     bool required = false;
00922     for (TCLAP::ArgVectorIterator it = xors.begin(); it != xors.end(); ++it) {
00923         if ((*it)->isRequired()) required = true;
00924     }
00925     for (TCLAP::ArgVectorIterator it = xors.begin(); it != xors.end(); ++it) {
00926         if (required) (*it)->forceRequired();
00927         (*it)->setRequireLabel("OR required");
00928         add(*it);
00929     }
00930 }
00931 
00932 // -----------------------------------------------------------------------
00933 void CmdLine::parse(int argc, const char * const * argv)
00934 {
00935     vector<string> args(argc);
00936     for (int i = 0; i < argc; i++) args[i] = argv[i];
00937     parse(args);
00938 }
00939 
00940 // -----------------------------------------------------------------------
00941 void CmdLine::parse(vector<string>& args)
00942 {
00943     bool shouldExit = false;
00944     int estat = 0;
00945 
00946     try {
00947         _progName = os::exename();
00948         args.erase(args.begin());
00949 
00950         int requiredCount = 0;
00951         for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) {
00952             bool matched = false;
00953             for (TCLAP::ArgListIterator it = _argList.begin(); it != _argList.end(); it++) {
00954                 if ((*it)->processArg(&i, args)) {
00955                     requiredCount += _xorHandler.check(*it);
00956                     matched = true;
00957                     break;
00958                 }
00959             }
00960             if (!matched && _emptyCombined(args[i])) matched = true;
00961             if (!matched && !TCLAP::Arg::ignoreRest()) {
00962                 throw TCLAP::CmdLineParseException("Couldn't find match for argument", args[i]);
00963             }
00964         }
00965 
00966         if (requiredCount < _numRequired) {
00967             string args;
00968             for (TCLAP::ArgListIterator it = _argList.begin(); it != _argList.end(); it++) {
00969                 if ((*it)->isRequired() && !(*it)->isSet()) {
00970                     args += (*it)->getName();
00971                     args += ", ";
00972                 }
00973             }
00974             args = args.substr(0, args.length() - 2);
00975             string msg = string("Not all required arguments specified, missing: ") + args;
00976             throw CmdLineParseException(msg);
00977         }
00978         if (requiredCount > _numRequired) {
00979             throw TCLAP::CmdLineParseException("Too many arguments given!");
00980         }
00981 
00982     } catch (TCLAP::ArgException& e) {
00983         if (!_handleExceptions) throw;
00984         try {
00985             _output->failure(*this, e);
00986         } catch (TCLAP::ExitException& ee) {
00987             estat = ee.getExitStatus();
00988             shouldExit = true;
00989         }
00990     } catch (TCLAP::ExitException& ee) {
00991         if (!_handleExceptions) throw;
00992         estat = ee.getExitStatus();
00993         shouldExit = true;
00994     }
00995 
00996     if (shouldExit) exit(estat);
00997 }
00998 
00999 
01000 } // namespace basis