CmdLine.cxx
Go to the documentation of this file.
1 // ============================================================================
2 // Copyright (c) 2011-2012 University of Pennsylvania
3 // Copyright (c) 2013-2016 Andreas Schuh
4 // All rights reserved.
5 //
6 // See COPYING file for license information or visit
7 // https://cmake-basis.github.io/download.html#license
8 // ============================================================================
9 
10 /**
11  * @file CmdLine.cxx
12  * @brief Manages command line definition and parsing of arguments.
13  */
14 
15 
16 #include <set>
17 
18 
19 #include <basis/tclap/Arg.h>
20 #include <basis/tclap/ArgException.h>
21 #include <basis/tclap/StdOutput.h>
22 #include <basis/tclap/Visitor.h>
23 #include <basis/tclap/VersionVisitor.h>
24 #include <basis/tclap/XorHandler.h>
25 
26 #include <basis/os.h> // exename()
27 #include <basis/except.h> // BASIS_THROW, runtime_error
28 #include <basis/stdio.h> // get_terminal_columns(), print_wrapped()
29 
30 #include <basis/CmdLine.h>
31 
32 
33 // acceptable in .cxx file
34 using namespace std;
35 
36 
37 namespace basis {
38 
39 
40 // ===========================================================================
41 // class: StdOutput
42 // ===========================================================================
43 
44 /**
45  * @brief Prints help, version information, and command-line errors.
46  */
47 class StdOutput : public TCLAP::CmdLineOutput
48 {
49  // -----------------------------------------------------------------------
50  // construction / destruction
51 public:
52 
53  /**
54  * @brief Constructor.
55  *
56  * @param [in] cmd The command-line with additional attributes
57  * for which the output is generated.
58  */
59  StdOutput(CmdLine* cmd);
60 
61  // -----------------------------------------------------------------------
62  // interface functions
63 public:
64 
65  /**
66  * @brief Prints a short help, i.e., usage information.
67  */
68  virtual void usage(TCLAP::CmdLineInterface&);
69 
70  /**
71  * @brief Prints the full help.
72  */
73  virtual void help(TCLAP::CmdLineInterface&);
74 
75  /**
76  * @brief Prints the version information.
77  */
78  virtual void version(TCLAP::CmdLineInterface&);
79 
80  /**
81  * @brief Prints an error message.
82  *
83  * @param [in] e The exception that caused the failure.
84  */
85  virtual void failure(TCLAP::CmdLineInterface&, TCLAP::ArgException& e);
86 
87  /**
88  * @brief Get corresponding command-line object.
89  *
90  * @returns Command-line with additional attributes for which the
91  * output is generated.
92  */
93  CmdLine* getCmdLine() { return _cmd; }
94 
95  // -----------------------------------------------------------------------
96  // helpers
97 protected:
98 
99  /**
100  * @brief Update information about terminal size.
101  */
102  void updateTerminalInfo();
103 
104  /**
105  * @brief Determine whether an argument has a label or not.
106  *
107  * @param [in] arg Command-line argument.
108  *
109  * @returns Whether the given argument is a positional argument.
110  */
111  bool isUnlabeledArg(TCLAP::Arg* arg) const;
112 
113  /**
114  * @brief Get string describing type of argument value.
115  *
116  * @param [in] arg Command-line argument.
117  *
118  * @returns String describing type of argument value.
119  */
120  string getTypeDescription(TCLAP::Arg* arg) const;
121 
122  /**
123  * @brief Get argument usage string.
124  *
125  * @param [in] arg Command-line argument.
126  * @param [in] all Whether to include also optional short flags.
127  *
128  * @returns Short argument description.
129  */
130  string getArgumentID(TCLAP::Arg* arg, bool all = false) const;
131 
132  /**
133  * @brief Prints help of command-line argument.
134  *
135  * @param [in] os Output stream.
136  * @param [in] arg Command-line argument.
137  * @param [in] indentFirstLine Whether first line should be indented.
138  */
139  void printArgumentHelp(ostream& os, TCLAP::Arg* arg, bool indentFirstLine = true) const;
140 
141  /**
142  * Prints usage information, i.e., synopsis.
143  *
144  * @param [in] os Output stream.
145  * @param [in] heading Enable/disable output of section heading.
146  */
147  void printUsage(ostream& os, bool heading = true) const;
148 
149  /**
150  * @brief Prints program description.
151  *
152  * @param [in] os Output stream.
153  */
154  void printDescription(ostream& os) const;
155 
156  /**
157  * @brief Prints command-line arguments.
158  *
159  * @param [in] os Output stream.
160  * @param [in] all Enable/disable help output of all arguments or only
161  * the more important arguments.
162  */
163  void printArguments(ostream& os, bool all) const;
164 
165  /**
166  * @brief Print example usage.
167  *
168  * @param [in] os Output stream.
169  */
170  void printExample(ostream& os) const;
171 
172  /**
173  * @brief Print contact information.
174  *
175  * @param [in] os Output stream.
176  */
177  void printContact(ostream& os) const;
178 
179  // -----------------------------------------------------------------------
180  // member variables
181 protected:
182 
183  CmdLine* _cmd; ///< The command-line with additional attributes.
184  set<string> _stdargs; ///< Names of standard arguments.
185  int _columns; ///< Maximum number of columns to use for output.
186 
187 }; // class StdOutput
188 
189 // ---------------------------------------------------------------------------
190 // construction
191 // ---------------------------------------------------------------------------
192 
193 // ---------------------------------------------------------------------------
194 StdOutput::StdOutput(CmdLine* cmd)
195 :
196  _cmd(cmd),
197  _columns(75)
198 {
199  _stdargs.insert("ignore_rest");
200  _stdargs.insert("verbose");
201  _stdargs.insert("help");
202  _stdargs.insert("helpshort");
203  _stdargs.insert("helpxml");
204  _stdargs.insert("helpman");
205  _stdargs.insert("version");
206 }
207 
208 // ---------------------------------------------------------------------------
209 // interface functions
210 // ---------------------------------------------------------------------------
211 
212 // ---------------------------------------------------------------------------
213 void StdOutput::usage(TCLAP::CmdLineInterface&)
214 {
215  updateTerminalInfo();
216  cout << endl;
217  printUsage(cout, false);
218  //printArguments(cout, false);
219  cout << endl;
220 }
221 
222 // ---------------------------------------------------------------------------
223 void StdOutput::help(TCLAP::CmdLineInterface&)
224 {
225  updateTerminalInfo();
226  cout << endl;
227  printUsage(cout);
228  printDescription(cout);
229  printArguments(cout, true);
230  printExample(cout);
231  printContact(cout);
232  cout << endl;
233 }
234 
235 // ---------------------------------------------------------------------------
236 void StdOutput::version(TCLAP::CmdLineInterface&)
237 {
238  std::string name = _cmd->getProgramName();
239  std::string project = _cmd->getProjectName();
240  std::string version = _cmd->getVersion();
241  std::string copyright = _cmd->getCopyright();
242  std::string license = _cmd->getLicense();
243 
244  // print version information
245  cout << name;
246  if (!project.empty()) cout << " (" << project << ")";
247  cout << " " << version;
248  cout << endl;
249  // print copyright and license information
250  if (!copyright.empty()) {
251  cout << "Copyright (c) " << copyright << ". All rights reserved." << endl;
252  }
253  if (!license.empty()) cout << license << endl;
254 }
255 
256 // ---------------------------------------------------------------------------
257 void StdOutput::failure(TCLAP::CmdLineInterface&, TCLAP::ArgException& e)
258 {
259  if (!e.argId().empty() && e.argId() != " ") cerr << e.argId() << ", ";
260  cerr << e.error() << endl;
261  cerr << "See --help for a list of available and required arguments." << endl;
262  throw TCLAP::ExitException(1);
263 }
264 
265 // ---------------------------------------------------------------------------
266 // helpers
267 // ---------------------------------------------------------------------------
268 
269 // ---------------------------------------------------------------------------
270 inline void StdOutput::updateTerminalInfo()
271 {
272  // get maximum number of columns
273  int columns = get_terminal_columns();
274  // update member variable, but maintain minimum number of columns
275  if (columns > 40) _columns = columns;
276 }
277 
278 // ---------------------------------------------------------------------------
279 inline bool StdOutput::isUnlabeledArg(TCLAP::Arg* arg) const
280 {
281  const string id = arg->longID();
282  string::size_type pos = id.find(TCLAP::Arg::nameStartString() + arg->getName());
283  return pos == string::npos;
284 }
285 
286 // ---------------------------------------------------------------------------
287 inline string StdOutput::getTypeDescription(TCLAP::Arg* arg) const
288 {
289  string typedesc = arg->shortID();
290  string::size_type start = typedesc.find ('<');
291  string::size_type end = typedesc.rfind('>');
292  if (start != string::npos && end != string::npos) {
293  return typedesc.substr(start + 1, end - start - 1);
294  } else {
295  return "";
296  }
297 }
298 
299 // ---------------------------------------------------------------------------
300 inline string StdOutput::getArgumentID(TCLAP::Arg* arg, bool all) const
301 {
302  string id;
303  const bool option = !isUnlabeledArg(arg);
304  if (option) {
305  if (all && arg->getFlag() != "") {
306  id += TCLAP::Arg::flagStartString() + arg->getFlag();
307  id += " ";
308  }
309  id += TCLAP::Arg::nameStartString() + arg->getName();
310  }
311  if (arg->isValueRequired()) {
312  if (option) id += TCLAP::Arg::delimiter();
313  id += getTypeDescription(arg);
314  }
315  return id;
316 }
317 
318 // ---------------------------------------------------------------------------
319 inline
320 void StdOutput::printArgumentHelp(ostream& os, TCLAP::Arg* arg, bool indentFirstLine) const
321 {
322  string id = getArgumentID(arg, true);
323  string desc = arg->getDescription();
324  if (desc.compare (0, 12, "(required) ") == 0) desc.erase(0, 12);
325  if (desc.compare (0, 15, "(OR required) ") == 0) desc.erase(0, 15);
326  if (indentFirstLine) print_wrapped(os, id, _columns, 8, 0);
327  else print_wrapped(os, id, _columns, 0, 8);
328  if (!desc.empty()) {
329  print_wrapped(os, desc, _columns, 15, 0);
330  }
331 }
332 
333 // ---------------------------------------------------------------------------
334 void StdOutput::printUsage(ostream& os, bool heading) const
335 {
336  string exec_name = os::exename();
337  list<TCLAP::Arg*> args = _cmd->getArgList();
338  TCLAP::XorHandler& xorhandler = _cmd->getXorHandler();
339  vector< vector<TCLAP::Arg*> > xors = xorhandler.getXorList();
340 
341  // separate into argument groups
342  vector< vector<TCLAP::Arg*> > reqxors;
343  vector< vector<TCLAP::Arg*> > optxors;
344  for (int i = 0; static_cast<unsigned int>(i) < xors.size(); i++) {
345  if (xors[i].size() > 0) {
346  if (xors[i][0]->isRequired()) reqxors.push_back(xors[i]);
347  else optxors.push_back(xors[i]);
348  }
349  }
350  list<TCLAP::Arg*> reqargs, reqposargs;
351  list<TCLAP::Arg*> optargs, optposargs;
352  for (TCLAP::ArgListIterator it = args.begin(); it != args.end(); it++) {
353  if (_stdargs.find((*it)->getName()) == _stdargs.end()
354  && !xorhandler.contains((*it))) {
355  if (isUnlabeledArg(*it)) {
356  if ((*it)->isRequired()) {
357  (*it)->addToList(reqposargs);
358  } else {
359  (*it)->addToList(optposargs);
360  }
361  } else {
362  if ((*it)->isRequired()) {
363  (*it)->addToList(reqargs);
364  } else {
365  (*it)->addToList(optargs);
366  }
367  }
368  }
369  }
370 
371  // executable name
372  string s = exec_name;
373  string id;
374  // optional arguments with flags
375  for (int i = 0; static_cast<unsigned int>(i) < optxors.size(); i++) {
376  s += " [";
377  for (TCLAP::ArgVectorIterator it = optxors[i].begin();
378  it != optxors[i].end(); it++) {
379  id = getArgumentID(*it);
380  s += id;
381  if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
382  s += "...";
383  }
384  s += "|";
385  }
386  s[s.length() - 1] = ']';
387  }
388  for (TCLAP::ArgListIterator it = optargs.begin(); it != optargs.end(); it++) {
389  id = getArgumentID(*it);
390  s += " [";
391  s += id;
392  s += "]";
393  if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
394  s += "...";
395  }
396  }
397  // required arguments with flags
398  for (int i = 0; static_cast<unsigned int>(i) < reqxors.size(); i++) {
399  s += " (";
400  for (TCLAP::ArgVectorIterator it = reqxors[i].begin();
401  it != reqxors[i].end(); it++) {
402  id = getArgumentID(*it);
403  s += id;
404  if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
405  s += "...";
406  }
407  s += "|";
408  }
409  s[s.length() - 1] = ')';
410  }
411  for (TCLAP::ArgListIterator it = reqargs.begin(); it != reqargs.end(); it++) {
412  id = getArgumentID(*it);
413  s += " ";
414  s += id;
415  if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
416  s += "...";
417  }
418  }
419  // required positional arguments
420  for (TCLAP::ArgListIterator it = reqposargs.begin(); it != reqposargs.end(); it++) {
421  id = getArgumentID(*it);
422  s += " ";
423  s += id;
424  if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
425  s += "...";
426  }
427  }
428  // optional positional arguments
429  for (TCLAP::ArgListIterator it = optposargs.begin(); it != optposargs.end(); it++) {
430  id = getArgumentID(*it);
431  s += " [";
432  s += id;
433  s += "]";
434  if ((*it)->acceptsMultipleValues() && id.find("...") == string::npos) {
435  s += "...";
436  }
437  }
438 
439  // print usage with proper number of columns
440  // if the program name is too long, then adjust the second line offset
441  if (heading) {
442  os << "SYNOPSIS" << endl;
443  }
444  int offset = static_cast<int>(exec_name.length()) + 1;
445  if (offset > _columns / 2) offset = 8;
446  print_wrapped(os, s, _columns, 4, offset);
447  print_wrapped(os, exec_name + " [-h|--help|--helpshort|--helpxml|--helpman|--version]", _columns, 4, offset);
448 }
449 
450 // ---------------------------------------------------------------------------
451 void StdOutput::printDescription(ostream& os) const
452 {
453  if (_cmd->getMessage() != "") {
454  os << endl;
455  os << "DESCRIPTION" << endl;
456  print_wrapped(os, _cmd->getMessage(), _columns, 4, 0);
457  }
458 }
459 
460 // ---------------------------------------------------------------------------
461 void StdOutput::printArguments(ostream& os, bool all) const
462 {
463  list<TCLAP::Arg*> args = _cmd->getArgList();
464  TCLAP::XorHandler& xorhandler = _cmd->getXorHandler();
465  vector< vector<TCLAP::Arg*> > xors = xorhandler.getXorList();
466 
467  // separate into argument groups
468  vector< vector<TCLAP::Arg*> > reqxors;
469  vector< vector<TCLAP::Arg*> > optxors;
470  for (int i = 0; static_cast<unsigned int>(i) < xors.size(); i++) {
471  if (xors[i].size() > 0) {
472  if (xors[i][0]->isRequired()) reqxors.push_back(xors[i]);
473  else optxors.push_back(xors[i]);
474  }
475  }
476  list<TCLAP::Arg*> reqargs, reqposargs;
477  list<TCLAP::Arg*> optargs, optposargs;
478  list<TCLAP::Arg*> stdargs;
479  for (TCLAP::ArgListIterator it = args.begin(); it != args.end(); it++) {
480  if (_stdargs.find((*it)->getName()) != _stdargs.end()) {
481  (*it)->addToList(stdargs);
482  } else if (!xorhandler.contains((*it))) {
483  if (isUnlabeledArg(*it)) {
484  if ((*it)->isRequired()) {
485  (*it)->addToList(reqposargs);
486  } else {
487  (*it)->addToList(optposargs);
488  }
489  } else {
490  if ((*it)->isRequired()) {
491  (*it)->addToList(reqargs);
492  } else {
493  (*it)->addToList(optargs);
494  }
495  }
496  }
497  }
498 
499  // return if command has no arguments
500  if (xors.empty() && reqargs.empty() && optargs.empty()) {
501  return;
502  }
503 
504  os << endl;
505  os << "OPTIONS" << endl;
506 
507  // required arguments
508  if (!reqxors.empty() || !reqargs.empty() || !reqposargs.empty()) {
509  os << " Required arguments:" << endl;
510  for (TCLAP::ArgListIterator it = reqposargs.begin(); it != reqposargs.end(); it++) {
511  if (it != reqposargs.begin()) os << endl;
512  printArgumentHelp(os, *it);
513  }
514  for (int i = 0; static_cast<unsigned int>(i) < reqxors.size(); i++) {
515  if (i > 0 || !reqposargs.empty()) os << endl;
516  for (TCLAP::ArgVectorIterator it = reqxors[i].begin();
517  it != reqxors[i].end(); it++) {
518  if (it != reqxors[i].begin()) {
519  os << " or ";
520  printArgumentHelp(os, *it, false);
521  } else {
522  printArgumentHelp(os, *it);
523  }
524  }
525  }
526  for (TCLAP::ArgListIterator it = reqargs.begin(); it != reqargs.end(); it++) {
527  if (!reqxors.empty() || it != reqargs.begin()) os << endl;
528  printArgumentHelp(os, *it);
529  }
530  }
531 
532  // optional arguments
533  if (!optxors.empty() || !optargs.empty()) {
534  if (!reqxors.empty() || !reqargs.empty() || !reqposargs.empty()) {
535  os << endl;
536  }
537  os << " Optional arguments:" << endl;
538  for (TCLAP::ArgListIterator it = optposargs.begin(); it != optposargs.end(); it++) {
539  if (it != optposargs.begin()) os << endl;
540  printArgumentHelp(os, *it);
541  }
542  for (int i = 0; static_cast<unsigned int>(i) < optxors.size(); i++) {
543  if (i > 0 || !optposargs.empty()) os << endl;
544  for (TCLAP::ArgVectorIterator it = optxors[i].begin();
545  it != optxors[i].end(); it++) {
546  if (it != optxors[i].begin()) {
547  os << " or ";
548  printArgumentHelp(os, *it, false);
549  } else {
550  printArgumentHelp(os, *it);
551  }
552  }
553  }
554  for (TCLAP::ArgListIterator it = optargs.begin(); it != optargs.end(); it++) {
555  if (!optxors.empty() || it != optargs.begin()) os << endl;
556  printArgumentHelp(os, *it);
557  }
558  }
559 
560  // standard arguments
561  if (all && !stdargs.empty()) {
562  if (!xors.empty() || !reqargs.empty() || !optargs.empty()) {
563  os << endl;
564  }
565  os << " Standard arguments:" << endl;
566  for (TCLAP::ArgListIterator it = stdargs.begin(); it != stdargs.end(); it++) {
567  if (it != stdargs.begin()) os << endl;
568  printArgumentHelp(os, *it);
569  }
570  }
571 }
572 
573 // ---------------------------------------------------------------------------
574 void StdOutput::printExample(ostream& os) const
575 {
576  const string exec_name = os::exename();
577  const vector<string>& examples = _cmd->getExamples();
578 
579  if (!examples.empty()) {
580  os << endl;
581  os << "EXAMPLE" << endl;
582  for (vector<string>::const_iterator it = examples.begin();
583  it != examples.end(); ++it) {
584  if (it != examples.begin()) os << endl;
585  string example = *it;
586  string::size_type pos;
587  // backwards compatibility
588  pos = 0;
589  while ((pos = example.find("EXECNAME", pos)) != string::npos) {
590  example.replace(pos, 8, exec_name);
591  }
592  // desired placeholder as it relates to the exename() function
593  pos = 0;
594  while ((pos = example.find("EXENAME", pos)) != string::npos) {
595  example.replace(pos, 7, exec_name);
596  }
597  print_wrapped(os, example, _columns, 4, 4);
598  }
599  }
600 }
601 
602 // ---------------------------------------------------------------------------
603 void StdOutput::printContact(ostream& os) const
604 {
605  if (_cmd->getContact() != "") {
606  os << endl;
607  os << "CONTACT" << endl;
608  print_wrapped(os, _cmd->getContact(), _columns, 4, 0);
609  }
610 }
611 
612 // ===========================================================================
613 // class: HelpVisitor
614 // ===========================================================================
615 
616 /**
617  * @brief Displays either full help or usage only.
618  */
619 class HelpVisitor: public TCLAP::Visitor
620 {
621  // -----------------------------------------------------------------------
622  // construction / destruction
623 public:
624 
625  /**
626  * @brief Constructor.
627  *
628  * @param [in] out The object which handles the output.
629  * @param [in] all Enable/disable full help output.
630  */
631  HelpVisitor(StdOutput* out, bool all = true)
632  :
633  Visitor(),
634  _out(out),
635  _all(all)
636  { }
637 
638  // -----------------------------------------------------------------------
639  // interface function
640 public:
641 
642  /**
643  * @brief Print help.
644  */
645  void visit()
646  {
647  if (_all) _out->help (*(_out->getCmdLine()));
648  else _out->usage(*(_out->getCmdLine()));
649  // exit
650  throw TCLAP::ExitException(0);
651  }
652 
653  // -----------------------------------------------------------------------
654  // member variables
655 protected:
656 
657  StdOutput* _out; ///< Object handling the output.
658  bool _all; ///< Enable/disable full help output.
659 
660  // -----------------------------------------------------------------------
661  // unsupported
662 private:
663 
664  HelpVisitor(const HelpVisitor&); ///< Not implemented.
665  HelpVisitor& operator=(const HelpVisitor&); ///< Not implemented.
666 
667 }; // class HelpVisitor
668 
669 // ===========================================================================
670 // class: XmlVisitor
671 // ===========================================================================
672 
673 /**
674  * @brief Outputs the command-line interface in XML format.
675  */
676 class XmlVisitor: public TCLAP::Visitor
677 {
678  // -----------------------------------------------------------------------
679  // construction / destruction
680 public:
681 
682  /**
683  * @brief Constructor.
684  */
685  XmlVisitor()
686  :
687  Visitor()
688  { }
689 
690  // -----------------------------------------------------------------------
691  // interface function
692 public:
693 
694  /**
695  * @brief Print help.
696  */
697  void visit()
698  {
699  cerr << "Not implemented yet! Use --help instead." << endl;
700  // exit
701  throw TCLAP::ExitException(0);
702  }
703 
704  // -----------------------------------------------------------------------
705  // member variables
706 protected:
707 
708 
709  // -----------------------------------------------------------------------
710  // unsupported
711 private:
712 
713  XmlVisitor(const XmlVisitor&); ///< Not implemented.
714  XmlVisitor& operator=(const XmlVisitor&); ///< Not implemented.
715 
716 }; // class XmlVisitor
717 
718 // ===========================================================================
719 // class: ManPageVisitor
720 // ===========================================================================
721 
722 /**
723  * @brief Displays man page and exits.
724  */
725 class ManPageVisitor: public TCLAP::Visitor
726 {
727  // -----------------------------------------------------------------------
728  // construction / destruction
729 public:
730 
731  /**
732  * @brief Constructor.
733  */
734  ManPageVisitor()
735  :
736  Visitor()
737  { }
738 
739  // -----------------------------------------------------------------------
740  // interface function
741 public:
742 
743  /**
744  * @brief Print help.
745  */
746  void visit()
747  {
748  cerr << "Not implemented yet! Use --help instead." << endl;
749  // exit
750  throw TCLAP::ExitException(0);
751  }
752 
753  // -----------------------------------------------------------------------
754  // member variables
755 protected:
756 
757 
758  // -----------------------------------------------------------------------
759  // unsupported
760 private:
761 
762  ManPageVisitor(const ManPageVisitor&); ///< Not implemented.
763  ManPageVisitor& operator=(const ManPageVisitor&); ///< Not implemented.
764 
765 }; // class ManPageVisitor
766 
767 // ===========================================================================
768 // class: CmdLine
769 // ===========================================================================
770 
771 // ---------------------------------------------------------------------------
772 CmdLine::CmdLine(const std::string& name,
773  const std::string& project,
774  const std::string& description,
775  const std::string& example,
776  const std::string& version,
777  const std::string& copyright,
778  const std::string& license,
779  const std::string& contact,
780  bool stdargs)
781 :
782  TCLAP::CmdLine(description, ' ', version, false),
783  _xorHandler(XorHandler()),
784  _name(name),
785  _project(project),
786  _copyright(copyright),
787  _license(license),
788  _contact(contact)
789 {
790  if (example != "") _examples.push_back(example);
791  setup(stdargs);
792 }
793 
794 // ---------------------------------------------------------------------------
795 CmdLine::CmdLine(const std::string& name,
796  const std::string& project,
797  const std::string& description,
798  const std::vector<std::string>& examples,
799  const std::string& version,
800  const std::string& copyright,
801  const std::string& license,
802  const std::string& contact,
803  bool stdargs)
804 :
805  TCLAP::CmdLine(description, ' ', version, false),
807  _name(name),
808  _project(project),
809  _examples(examples),
810  _copyright(copyright),
811  _license(license),
812  _contact(contact)
813 {
814  setup(stdargs);
815 }
816 
817 // ---------------------------------------------------------------------------
818 void CmdLine::setup(bool stdargs)
819 {
820  // replace output handler
821  StdOutput* output = new StdOutput(this);
822  if (_output) delete _output;
823  _output = output;
824 
825  // remove arguments added by TCLAP::CmdLine (ignore)
826  ClearContainer(_argDeleteOnExitList);
827  ClearContainer(_visitorDeleteOnExitList);
828  TCLAP::CmdLine::_argList.clear();
829 
830  // add standard arguments
831  TCLAP::Visitor* v;
832 
833  v = new TCLAP::IgnoreRestVisitor();
834  SwitchArg* ignore = new SwitchArg(
835  TCLAP::Arg::flagStartString(), TCLAP::Arg::ignoreNameString(),
836  "Ignores the rest of the labeled arguments.",
837  false, v);
838  add(ignore);
839  deleteOnExit(ignore);
840  deleteOnExit(v);
841 
842  if (stdargs) {
843  v = new HelpVisitor(output, true);
845  "h", "help", "Display help and exit.", false, v);
846  add(help);
847  deleteOnExit(help);
848  deleteOnExit(v);
849 
850  v = new HelpVisitor(output, false);
851  TCLAP::SwitchArg* helpshort = new TCLAP::SwitchArg(
852  "", "helpshort", "Display short help and exit.", false, v);
853  add(helpshort);
854  deleteOnExit(helpshort);
855  deleteOnExit(v);
856 
857  v = new XmlVisitor();
858  TCLAP::SwitchArg* helpxml = new TCLAP::SwitchArg(
859  "", "helpxml", "Display help in XML format and exit.", false, v);
860  add(helpxml);
861  deleteOnExit(helpxml);
862  deleteOnExit(v);
863 
864  v = new ManPageVisitor();
865  TCLAP::SwitchArg* helpman = new TCLAP::SwitchArg(
866  "", "helpman", "Display help as man page and exit.", false, v);
867  add(helpman);
868  deleteOnExit(helpman);
869  deleteOnExit(v);
870 
871  v = new TCLAP::VersionVisitor(this, &_output);
873  "", "version", "Display version information and exit.", false, v);
874  add(vers);
875  deleteOnExit(vers);
876  deleteOnExit(v);
877  }
878 }
879 
880 // -----------------------------------------------------------------------
882 {
883  TCLAP::CmdLine::add(a);
884 }
885 
886 // -----------------------------------------------------------------------
888 {
889  TCLAP::CmdLine::add(a);
890 }
891 
892 // -----------------------------------------------------------------------
893 void CmdLine::xorAdd(Arg& a, Arg& b)
894 {
895  vector<TCLAP::Arg*> xors;
896  xors.push_back(&a);
897  xors.push_back(&b);
898  xorAdd(xors);
899 }
900 
901 // -----------------------------------------------------------------------
903 {
904  _output->usage(*const_cast<CmdLine*>(this));
905 }
906 
907 // -----------------------------------------------------------------------
909 {
910  StdOutput* output = dynamic_cast<StdOutput*>(_output);
911  if (output) output ->help (*const_cast<CmdLine*>(this));
912  else _output->usage(*const_cast<CmdLine*>(this));
913 }
914 
915 // -----------------------------------------------------------------------
917 {
918  _output->version(*const_cast<CmdLine*>(this));
919 }
920 
921 // -----------------------------------------------------------------------
922 void CmdLine::xorAdd(vector<Arg*>& xors)
923 {
924  _xorHandler.add(xors);
925  bool required = false;
926  for (TCLAP::ArgVectorIterator it = xors.begin(); it != xors.end(); ++it) {
927  if ((*it)->isRequired()) required = true;
928  }
929  for (TCLAP::ArgVectorIterator it = xors.begin(); it != xors.end(); ++it) {
930  if (required) (*it)->forceRequired();
931  (*it)->setRequireLabel("OR required");
932  add(*it);
933  }
934 }
935 
936 // -----------------------------------------------------------------------
937 void CmdLine::parse(int argc, const char * const * argv)
938 {
939  vector<string> args(argc);
940  for (int i = 0; i < argc; i++) args[i] = argv[i];
941  parse(args);
942 }
943 
944 // -----------------------------------------------------------------------
945 void CmdLine::parse(vector<string>& args)
946 {
947  bool shouldExit = false;
948  int estat = 0;
949 
950  try {
951  _progName = os::exename();
952  args.erase(args.begin());
953 
954  int requiredCount = 0;
955  for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) {
956  bool matched = false;
957  for (TCLAP::ArgListIterator it = _argList.begin(); it != _argList.end(); it++) {
958  if ((*it)->processArg(&i, args)) {
959  requiredCount += _xorHandler.check(*it);
960  matched = true;
961  break;
962  }
963  }
964  if (!matched && _emptyCombined(args[i])) matched = true;
965  if (!matched && !TCLAP::Arg::ignoreRest()) {
966  throw TCLAP::CmdLineParseException("Couldn't find match for argument", args[i]);
967  }
968  }
969 
970  if (requiredCount < _numRequired) {
971  string args;
972  for (TCLAP::ArgListIterator it = _argList.begin(); it != _argList.end(); it++) {
973  if ((*it)->isRequired() && !(*it)->isSet()) {
974  args += (*it)->getName();
975  args += ", ";
976  }
977  }
978  args = args.substr(0, args.length() - 2);
979  string msg = string("Not all required arguments specified, missing: ") + args;
980  throw CmdLineParseException(msg);
981  }
982  if (requiredCount > _numRequired) {
983  throw TCLAP::CmdLineParseException("Too many arguments given!");
984  }
985 
986  } catch (TCLAP::ArgException& e) {
987  if (!_handleExceptions) throw;
988  try {
989  _output->failure(*this, e);
990  } catch (TCLAP::ExitException& ee) {
991  estat = ee.getExitStatus();
992  shouldExit = true;
993  }
994  } catch (TCLAP::ExitException& ee) {
995  if (!_handleExceptions) throw;
996  estat = ee.getExitStatus();
997  shouldExit = true;
998  }
999 
1000  if (shouldExit) exit(estat);
1001 }
1002 
1003 
1004 } // namespace basis
void xorAdd(Arg &a, Arg &b)
Add two Args that will be xor&#39;d.
Definition: CmdLine.cxx:893
Basic exceptions and related helper macros.
void setup(bool stdargs)
Set up command-line object.
Definition: CmdLine.cxx:818
XorHandler _xorHandler
Customized XorHandler.
Definition: CmdLine.h:304
void parse(int argc, const char *const *argv)
Parses the command line.
Definition: CmdLine.cxx:937
void print_usage() const
Print short help, i.e., usage information.
Definition: CmdLine.cxx:902
TCLAP::SwitchArg SwitchArg
Switch to enable/disable option.
Definition: CmdArgs.h:53
STL namespace.
std::string _name
Program name.
Definition: CmdLine.h:305
Definition: basis.h:34
std::string _project
Name of project.
Definition: CmdLine.h:306
std::string exename()
Get name of executable.
Definition: os.cxx:127
std::string _copyright
Program copyright.
Definition: CmdLine.h:308
CmdLine(const std::string &name, const std::string &project, const std::string &description, const std::string &example, const std::string &version, const std::string &copyright="Copyright (c) University of Pennsylvania." " All rights reserved.", const std::string &license="See http://www.rad.upenn.edu/sbia/software/license.html" " or COPYING file.", const std::string &contact="SBIA Group <sbia-software at uphs.upenn.edu>", bool stdargs=true)
Constructor.
Definition: CmdLine.cxx:772
std::ostream & print_wrapped(std::ostream &os, const std::string &text, int width, int indent, int offset)
Print text, wrapped at a fixed maximum number of columns.
Definition: stdio.cxx:99
TCLAP::ArgException ArgException
Exception thrown by command-line parsing library.
Definition: except.h:60
int check(const Arg *a)
Checks whether the specified Arg is in one of the xor lists.
Definition: CmdLine.h:73
Operating system dependent functions.
TCLAP::Arg Arg
Base type of command-line arguments.
Definition: CmdArgs.h:47
Manages command line definition and parsing of arguments.
Definition: CmdLine.h:37
std::string _contact
Contact information.
Definition: CmdLine.h:310
std::string _license
Program license.
Definition: CmdLine.h:309
Standard I/O functions.
Handles lists of Arg&#39;s that are to be XOR&#39;d on the command-line.
Definition: CmdLine.h:55
void add(Arg &a)
Adds an argument to the list of arguments to be parsed.
Definition: CmdLine.cxx:881
cmake msg
int get_terminal_columns()
Get maximum number of columns of terminal window.
Definition: stdio.cxx:91
void print_help() const
Print help.
Definition: CmdLine.cxx:908
Manages command line definition and parsing of arguments.
std::vector< std::string > _examples
Program usage example.
Definition: CmdLine.h:307
TCLAP::ExitException ExitException
Exception thrown by command-line parsing library to indicate that program should exit with the given ...
Definition: except.h:64
void print_version() const
Print version information.
Definition: CmdLine.cxx:916
TCLAP::CmdLineParseException CmdLineParseException
Exception thrown on command-line parsing error.
Definition: except.h:70
virtual std::string description() const
Definition: CmdArgs.h:259