00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <set>
00013
00014 #include <sbia/tclap/Arg.h>
00015 #include <sbia/tclap/ArgException.h>
00016 #include <sbia/tclap/StdOutput.h>
00017 #include <sbia/tclap/Visitor.h>
00018 #include <sbia/tclap/VersionVisitor.h>
00019 #include <sbia/tclap/XorHandler.h>
00020
00021 #include <sbia/basis/path.h>
00022 #include <sbia/basis/except.h>
00023
00024 #include <sbia/basis/CmdLine.h>
00025
00026
00027
00028 using namespace std;
00029
00030
00031 namespace sbia
00032 {
00033
00034 namespace basis
00035 {
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 class StdOutput : public TCLAP::StdOutput
00046 {
00047
00048
00049 public:
00050
00051
00052
00053
00054
00055
00056
00057 StdOutput(CmdLine* cmd);
00058
00059
00060
00061 public:
00062
00063
00064
00065
00066 virtual void usage(TCLAP::CmdLineInterface&);
00067
00068
00069
00070
00071 virtual void help(TCLAP::CmdLineInterface&);
00072
00073
00074
00075
00076 virtual void version(TCLAP::CmdLineInterface&);
00077
00078
00079
00080
00081
00082
00083 virtual void failure(TCLAP::CmdLineInterface&, TCLAP::ArgException& e);
00084
00085
00086
00087
00088
00089
00090
00091 CmdLine* getCmdLine() { return _cmd; }
00092
00093
00094
00095 protected:
00096
00097
00098
00099
00100
00101
00102
00103
00104 bool isUnlabeledArg(TCLAP::Arg* arg) const;
00105
00106
00107
00108
00109
00110
00111
00112
00113 string getTypeDescription(TCLAP::Arg* arg) const;
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 string getArgumentID(TCLAP::Arg* arg, bool all = false) const;
00124
00125
00126
00127
00128
00129
00130
00131
00132 void printArgumentHelp(ostream& os, TCLAP::Arg* arg, bool indentFirstLine = true) const;
00133
00134
00135
00136
00137
00138
00139
00140 void printUsage(ostream& os, bool heading = true) const;
00141
00142
00143
00144
00145
00146
00147 void printDescription(ostream& os) const;
00148
00149
00150
00151
00152
00153
00154
00155
00156 void printArguments(ostream& os, bool all) const;
00157
00158
00159
00160
00161
00162
00163 void printExample(ostream& os) const;
00164
00165
00166
00167
00168
00169
00170 void printContact(ostream& os) const;
00171
00172
00173
00174 protected:
00175
00176 CmdLine* _cmd;
00177 set<string> _stdargs;
00178
00179 };
00180
00181
00182
00183
00184
00185
00186 StdOutput::StdOutput(CmdLine* cmd)
00187 :
00188 _cmd(cmd)
00189 {
00190 _stdargs.insert("ignore_rest");
00191 _stdargs.insert("verbose");
00192 _stdargs.insert("help");
00193 _stdargs.insert("helpshort");
00194 _stdargs.insert("helpxml");
00195 _stdargs.insert("helpman");
00196 _stdargs.insert("version");
00197 }
00198
00199
00200
00201
00202
00203
00204 void StdOutput::usage(TCLAP::CmdLineInterface&)
00205 {
00206 cout << endl;
00207 printUsage(cout, false);
00208
00209 cout << endl;
00210 }
00211
00212
00213 void StdOutput::help(TCLAP::CmdLineInterface&)
00214 {
00215 cout << endl;
00216 printUsage(cout);
00217 printDescription(cout);
00218 printArguments(cout, true);
00219 printExample(cout);
00220 printContact(cout);
00221 cout << endl;
00222 }
00223
00224
00225 void StdOutput::version(TCLAP::CmdLineInterface&)
00226 {
00227 std::string name = _cmd->getProgramName();
00228 std::string project = _cmd->getProjectName();
00229 std::string version = _cmd->getVersion();
00230 std::string copyright = _cmd->getCopyright();
00231 std::string license = _cmd->getLicense();
00232
00233
00234 cout << name;
00235 if (!project.empty()) cout << " (" << project << ")";
00236 cout << " " << version;
00237 cout << endl;
00238
00239 if (!copyright.empty()) cout << copyright << endl;
00240 if (!license.empty()) cout << license << endl;
00241 }
00242
00243
00244 void StdOutput::failure(TCLAP::CmdLineInterface&, TCLAP::ArgException& e)
00245 {
00246 if (!e.argId().empty() && e.argId() != " ") cerr << e.argId() << ", ";
00247 cerr << e.error() << endl;
00248 cerr << "See --help for a list of available and required arguments." << endl;
00249 throw TCLAP::ExitException(1);
00250 }
00251
00252
00253
00254
00255
00256
00257 inline bool StdOutput::isUnlabeledArg(TCLAP::Arg* arg) const
00258 {
00259 const string id = arg->longID();
00260 string::size_type pos = id.find(TCLAP::Arg::nameStartString() + arg->getName());
00261 return pos == string::npos;
00262 }
00263
00264
00265 inline string StdOutput::getTypeDescription(TCLAP::Arg* arg) const
00266 {
00267 string typedesc = arg->shortID();
00268 string::size_type start = typedesc.find ('<');
00269 string::size_type end = typedesc.rfind('>');
00270 if (start != string::npos && end != string::npos) {
00271 return typedesc.substr(start + 1, end - start - 1);
00272 } else {
00273 return "";
00274 }
00275 }
00276
00277
00278 inline string StdOutput::getArgumentID(TCLAP::Arg* arg, bool all) const
00279 {
00280 string id;
00281 const bool option = !isUnlabeledArg(arg);
00282 if (option) {
00283 if (all && arg->getFlag() != "") {
00284 id += TCLAP::Arg::flagStartString() + arg->getFlag();
00285 id += " ";
00286 }
00287 id += TCLAP::Arg::nameStartString() + arg->getName();
00288 }
00289 if (arg->isValueRequired()) {
00290 if (option) id += TCLAP::Arg::delimiter();
00291 id += getTypeDescription(arg);
00292 }
00293 return id;
00294 }
00295
00296
00297 inline
00298 void StdOutput
00299 ::printArgumentHelp(ostream& os, TCLAP::Arg* arg, bool indentFirstLine) const
00300 {
00301 string id = getArgumentID(arg, true);
00302 string desc = arg->getDescription();
00303 if (desc.compare (0, 12, "(required) ") == 0) desc.erase(0, 12);
00304 if (desc.compare (0, 15, "(OR required) ") == 0) desc.erase(0, 15);
00305 if (indentFirstLine) spacePrint(os, id, 75, 8, 0);
00306 else spacePrint(os, id, 75, 0, 8);
00307 if (!desc.empty()) {
00308 spacePrint(os, desc, 75, 15, 0);
00309 }
00310 }
00311
00312
00313 void StdOutput::printUsage(ostream& os, bool heading) const
00314 {
00315 string exec_name = get_executable_name();
00316 list<TCLAP::Arg*> args = _cmd->getArgList();
00317 TCLAP::XorHandler xorhandler = _cmd->getXorHandler();
00318 vector< vector<TCLAP::Arg*> > xors = xorhandler.getXorList();
00319
00320
00321 vector< vector<TCLAP::Arg*> > reqxors;
00322 vector< vector<TCLAP::Arg*> > optxors;
00323 for (int i = 0; static_cast<unsigned int>(i) < xors.size(); i++) {
00324 if (xors[i].size() > 0) {
00325 if (xors[i][0]->isRequired()) reqxors.push_back(xors[i]);
00326 else optxors.push_back(xors[i]);
00327 }
00328 }
00329 list<TCLAP::Arg*> reqargs;
00330 list<TCLAP::Arg*> optargs;
00331 for (TCLAP::ArgListIterator it = args.begin(); it != args.end(); it++) {
00332 if (_stdargs.find((*it)->getName()) == _stdargs.end()
00333 && !xorhandler.contains((*it))) {
00334 if ((*it)->isRequired()) {
00335 reqargs.push_front(*it);
00336 } else {
00337 optargs.push_front(*it);
00338 }
00339 }
00340 }
00341
00342
00343 string s = exec_name;
00344 string id;
00345
00346 for (int i = 0; static_cast<unsigned int>(i) < optxors.size(); i++) {
00347 s += " [";
00348 for (TCLAP::ArgVectorIterator it = optxors[i].begin();
00349 it != optxors[i].end(); it++) {
00350 id = getArgumentID(*it);
00351 s += id;
00352 if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00353 s += "...";
00354 }
00355 s += "|";
00356 }
00357 s[s.length() - 1] = ']';
00358 }
00359 for (TCLAP::ArgListIterator it = optargs.begin(); it != optargs.end(); it++) {
00360 id = getArgumentID(*it);
00361 s += " [";
00362 s += id;
00363 s += "]";
00364 if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00365 s += "...";
00366 }
00367 }
00368
00369 for (int i = 0; static_cast<unsigned int>(i) < reqxors.size(); i++) {
00370 s += " (";
00371 for (TCLAP::ArgVectorIterator it = reqxors[i].begin();
00372 it != reqxors[i].end(); it++) {
00373 id = getArgumentID(*it);
00374 s += id;
00375 if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00376 s += "...";
00377 }
00378 s += "|";
00379 }
00380 s[s.length() - 1] = ')';
00381 }
00382 for (TCLAP::ArgListIterator it = reqargs.begin(); it != reqargs.end(); it++) {
00383 id = getArgumentID(*it);
00384 s += " ";
00385 s += id;
00386 if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
00387 s += "...";
00388 }
00389 }
00390
00391
00392
00393 if (heading) {
00394 os << "SYNOPSIS" << endl;
00395 }
00396 int offset = static_cast<int>(exec_name.length()) + 1;
00397 if (offset > 75 / 2) offset = 8;
00398 spacePrint(os, s, 75, 4, offset);
00399 spacePrint(os, exec_name + " [-h|--help|--helpshort|--helpxml|--helpman|--version]", 75, 4, 0);
00400 }
00401
00402
00403 void StdOutput::printDescription(ostream& os) const
00404 {
00405 if (_cmd->getMessage() != "") {
00406 os << endl;
00407 os << "DESCRIPTION" << endl;
00408 spacePrint(os, _cmd->getMessage(), 75, 4, 0);
00409 }
00410 }
00411
00412
00413 void StdOutput::printArguments(ostream& os, bool all) const
00414 {
00415 list<TCLAP::Arg*> args = _cmd->getArgList();
00416 TCLAP::XorHandler xorhandler = _cmd->getXorHandler();
00417 vector< vector<TCLAP::Arg*> > xors = xorhandler.getXorList();
00418
00419
00420 vector< vector<TCLAP::Arg*> > reqxors;
00421 vector< vector<TCLAP::Arg*> > optxors;
00422 for (int i = 0; static_cast<unsigned int>(i) < xors.size(); i++) {
00423 if (xors[i].size() > 0) {
00424 if (xors[i][0]->isRequired()) reqxors.push_back(xors[i]);
00425 else optxors.push_back(xors[i]);
00426 }
00427 }
00428 list<TCLAP::Arg*> reqargs;
00429 list<TCLAP::Arg*> optargs;
00430 list<TCLAP::Arg*> stdargs;
00431 for (TCLAP::ArgListIterator it = args.begin(); it != args.end(); it++) {
00432 if (_stdargs.find((*it)->getName()) != _stdargs.end()) {
00433 stdargs.push_front(*it);
00434 } else if (!xorhandler.contains((*it))) {
00435 if ((*it)->isRequired()) {
00436 reqargs.push_front(*it);
00437 } else {
00438 optargs.push_front(*it);
00439 }
00440 }
00441 }
00442
00443
00444 if (xors.empty() && reqargs.empty() && optargs.empty()) {
00445 return;
00446 }
00447
00448 os << endl;
00449 os << "OPTIONS" << endl;
00450
00451
00452 if (!reqxors.empty() || !reqargs.empty()) {
00453 os << " Required arguments:" << endl;
00454 for (int i = 0; static_cast<unsigned int>(i) < reqxors.size(); i++) {
00455 if (i > 0) os << endl;
00456 for (TCLAP::ArgVectorIterator it = reqxors[i].begin();
00457 it != reqxors[i].end(); it++) {
00458 if (it != reqxors[i].begin()) {
00459 os << " or ";
00460 printArgumentHelp(os, *it, false);
00461 } else {
00462 printArgumentHelp(os, *it);
00463 }
00464 }
00465 }
00466 for (TCLAP::ArgListIterator it = reqargs.begin(); it != reqargs.end(); it++) {
00467 if (!reqxors.empty() || it != reqargs.begin()) os << endl;
00468 printArgumentHelp(os, *it);
00469 }
00470 }
00471
00472
00473 if (!optxors.empty() || !optargs.empty()) {
00474 if (!reqxors.empty() || !reqargs.empty()) {
00475 os << endl;
00476 }
00477 os << " Optional arguments:" << endl;
00478 for (int i = 0; static_cast<unsigned int>(i) < optxors.size(); i++) {
00479 if (i > 0) os << endl;
00480 for (TCLAP::ArgVectorIterator it = optxors[i].begin();
00481 it != optxors[i].end(); it++) {
00482 if (it != optxors[i].begin()) {
00483 os << " or ";
00484 printArgumentHelp(os, *it, false);
00485 } else {
00486 printArgumentHelp(os, *it);
00487 }
00488 }
00489 }
00490 for (TCLAP::ArgListIterator it = optargs.begin(); it != optargs.end(); it++) {
00491 if (!optxors.empty() || it != optargs.begin()) os << endl;
00492 printArgumentHelp(os, *it);
00493 }
00494 }
00495
00496
00497 if (all && !stdargs.empty()) {
00498 if (!xors.empty() || !reqargs.empty() || !optargs.empty()) {
00499 os << endl;
00500 }
00501 os << " Standard arguments:" << endl;
00502 for (TCLAP::ArgListIterator it = stdargs.begin(); it != stdargs.end(); it++) {
00503 if (it != stdargs.begin()) os << endl;
00504 printArgumentHelp(os, *it);
00505 }
00506 }
00507 }
00508
00509
00510 void StdOutput::printExample(ostream& os) const
00511 {
00512 const string exec_name = get_executable_name();
00513 const vector<string>& examples = _cmd->getExamples();
00514
00515 if (!examples.empty()) {
00516 os << endl;
00517 os << "EXAMPLE" << endl;
00518 for (vector<string>::const_iterator it = examples.begin();
00519 it != examples.end(); ++it) {
00520 if (it != examples.begin()) os << endl;
00521 string example = *it;
00522 string::size_type pos = 0;
00523 while ((pos = example.find("EXECNAME", pos)) != string::npos) {
00524 example.replace(pos, 8, exec_name);
00525 }
00526 spacePrint(os, example, 75, 4, 4);
00527 }
00528 }
00529 }
00530
00531
00532 void StdOutput::printContact(ostream& os) const
00533 {
00534 if (_cmd->getContact() != "") {
00535 os << endl;
00536 os << "CONTACT" << endl;
00537 spacePrint(os, _cmd->getContact(), 75, 4, 0);
00538 }
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548 class HelpVisitor: public TCLAP::Visitor
00549 {
00550
00551
00552 public:
00553
00554
00555
00556
00557
00558
00559
00560 HelpVisitor(StdOutput* out, bool all = true)
00561 :
00562 Visitor(),
00563 _out(out),
00564 _all(all)
00565 { }
00566
00567
00568
00569 public:
00570
00571
00572
00573
00574 void visit()
00575 {
00576 if (_all) _out->help (*(_out->getCmdLine()));
00577 else _out->usage(*(_out->getCmdLine()));
00578
00579 throw TCLAP::ExitException(0);
00580 }
00581
00582
00583
00584 protected:
00585
00586 StdOutput* _out;
00587 bool _all;
00588
00589
00590
00591 private:
00592
00593 HelpVisitor(const HelpVisitor&);
00594 HelpVisitor& operator=(const HelpVisitor&);
00595
00596 };
00597
00598
00599
00600
00601
00602
00603
00604
00605 class XmlVisitor: public TCLAP::Visitor
00606 {
00607
00608
00609 public:
00610
00611
00612
00613
00614 XmlVisitor()
00615 :
00616 Visitor()
00617 { }
00618
00619
00620
00621 public:
00622
00623
00624
00625
00626 void visit()
00627 {
00628 cerr << "Not implemented yet! Use --help instead." << endl;
00629
00630 throw TCLAP::ExitException(0);
00631 }
00632
00633
00634
00635 protected:
00636
00637
00638
00639
00640 private:
00641
00642 XmlVisitor(const XmlVisitor&);
00643 XmlVisitor& operator=(const XmlVisitor&);
00644
00645 };
00646
00647
00648
00649
00650
00651
00652
00653
00654 class ManPageVisitor: public TCLAP::Visitor
00655 {
00656
00657
00658 public:
00659
00660
00661
00662
00663 ManPageVisitor()
00664 :
00665 Visitor()
00666 { }
00667
00668
00669
00670 public:
00671
00672
00673
00674
00675 void visit()
00676 {
00677 cerr << "Not implemented yet! Use --help instead." << endl;
00678
00679 throw TCLAP::ExitException(0);
00680 }
00681
00682
00683
00684 protected:
00685
00686
00687
00688
00689 private:
00690
00691 ManPageVisitor(const ManPageVisitor&);
00692 ManPageVisitor& operator=(const ManPageVisitor&);
00693
00694 };
00695
00696
00697
00698
00699
00700
00701 CmdLine::CmdLine(const std::string& name,
00702 const std::string& project,
00703 const std::string& description,
00704 const std::string& example,
00705 const std::string& version,
00706 const std::string& copyright,
00707 const std::string& license,
00708 const std::string& contact,
00709 bool stdargs)
00710 :
00711 TCLAP::CmdLine(description, ' ', version, false),
00712 _name(name),
00713 _project(project),
00714 _copyright(copyright),
00715 _license(license),
00716 _contact(contact)
00717 {
00718 if (example != "") _examples.push_back(example);
00719 setup(stdargs);
00720 }
00721
00722
00723 CmdLine::CmdLine(const std::string& name,
00724 const std::string& project,
00725 const std::string& description,
00726 const std::vector<std::string>& examples,
00727 const std::string& version,
00728 const std::string& copyright,
00729 const std::string& license,
00730 const std::string& contact,
00731 bool stdargs)
00732 :
00733 TCLAP::CmdLine(description, ' ', version, false),
00734 _name(name),
00735 _project(project),
00736 _examples(examples),
00737 _copyright(copyright),
00738 _license(license),
00739 _contact(contact)
00740 {
00741 setup(stdargs);
00742 }
00743
00744
00745 void CmdLine::setup(bool stdargs)
00746 {
00747
00748 StdOutput* output = new StdOutput(this);
00749 if (_output) delete _output;
00750 _output = output;
00751
00752
00753 ClearContainer(_argDeleteOnExitList);
00754 ClearContainer(_visitorDeleteOnExitList);
00755 TCLAP::CmdLine::_argList.clear();
00756
00757
00758 TCLAP::Visitor* v;
00759
00760 v = new TCLAP::IgnoreRestVisitor();
00761 SwitchArg* ignore = new SwitchArg(
00762 TCLAP::Arg::flagStartString(), TCLAP::Arg::ignoreNameString(),
00763 "Ignores the rest of the labeled arguments.",
00764 false, v);
00765 add(ignore);
00766 deleteOnExit(ignore);
00767 deleteOnExit(v);
00768
00769 if (stdargs) {
00770 v = new HelpVisitor(output, true);
00771 TCLAP::SwitchArg* help = new TCLAP::SwitchArg(
00772 "h", "help", "Display help and exit.", false, v);
00773 add(help);
00774 deleteOnExit(help);
00775 deleteOnExit(v);
00776
00777 v = new HelpVisitor(output, false);
00778 TCLAP::SwitchArg* helpshort = new TCLAP::SwitchArg(
00779 "", "helpshort", "Display short help and exit.", false, v);
00780 add(helpshort);
00781 deleteOnExit(helpshort);
00782 deleteOnExit(v);
00783
00784 v = new XmlVisitor();
00785 TCLAP::SwitchArg* helpxml = new TCLAP::SwitchArg(
00786 "", "helpxml", "Display help in XML format and exit.", false, v);
00787 add(helpxml);
00788 deleteOnExit(helpxml);
00789 deleteOnExit(v);
00790
00791 v = new ManPageVisitor();
00792 TCLAP::SwitchArg* helpman = new TCLAP::SwitchArg(
00793 "", "helpman", "Display help as man page and exit.", false, v);
00794 add(helpman);
00795 deleteOnExit(helpman);
00796 deleteOnExit(v);
00797
00798 v = new TCLAP::VersionVisitor(this, &_output);
00799 TCLAP::SwitchArg* vers = new TCLAP::SwitchArg(
00800 "", "version", "Display version information and exit.", false, v);
00801 add(vers);
00802 deleteOnExit(vers);
00803 deleteOnExit(v);
00804 }
00805 }
00806
00807
00808
00809
00810
00811 void CmdLine::add(Arg& a)
00812 {
00813 TCLAP::CmdLine::add(a);
00814 }
00815
00816
00817 void CmdLine::add(Arg* a)
00818 {
00819 TCLAP::CmdLine::add(a);
00820 }
00821
00822
00823 void CmdLine::xorAdd(Arg& a, Arg& b)
00824 {
00825 vector<TCLAP::Arg*> xors;
00826 xors.push_back(&a);
00827 xors.push_back(&b);
00828 xorAdd(xors);
00829 }
00830
00831
00832 void CmdLine::xorAdd(std::vector<Arg*>& xors)
00833 {
00834 TCLAP::CmdLine::_xorHandler.add(xors);
00835
00836 bool required = false;
00837 for (TCLAP::ArgVectorIterator it = xors.begin(); it != xors.end(); ++it) {
00838 if ((*it)->isRequired()) required = true;
00839 }
00840 for (TCLAP::ArgVectorIterator it = xors.begin(); it != xors.end(); ++it) {
00841 if (required) (*it)->forceRequired();
00842 (*it)->setRequireLabel("OR required");
00843 add( *it );
00844 }
00845 }
00846
00847
00848 void CmdLine::parse(int argc, const char* const* argv)
00849 {
00850 TCLAP::CmdLine::parse(argc, argv);
00851 }
00852
00853
00854 void CmdLine::parse(std::vector<std::string>& args)
00855 {
00856 TCLAP::CmdLine::parse(args);
00857 }
00858
00859
00860 }
00861
00862 }