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