tclap  1.4.0
CmdLine.h
Go to the documentation of this file.
1 // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
2 
3 /******************************************************************************
4  *
5  * file: CmdLine.h
6  *
7  * Copyright (c) 2003, Michael E. Smoot .
8  * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
9  * Copyright (c) 2018, Google LLC
10  * All rights reserved.
11  *
12  * See the file COPYING in the top directory of this distribution for
13  * more information.
14  *
15  * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  *****************************************************************************/
24 
25 #ifndef TCLAP_CMD_LINE_H
26 #define TCLAP_CMD_LINE_H
27 
28 #include <tclap/MultiSwitchArg.h>
29 #include <tclap/SwitchArg.h>
32 
33 #include <tclap/HelpVisitor.h>
35 #include <tclap/VersionVisitor.h>
36 
37 #include <tclap/CmdLineOutput.h>
38 #include <tclap/StdOutput.h>
39 
40 #include <tclap/Constraint.h>
41 #include <tclap/ValuesConstraint.h>
42 
43 #include <tclap/ArgGroup.h>
44 #include <tclap/DeferDelete.h>
45 
46 #include <algorithm>
47 #include <cstdlib>
48 #include <iomanip>
49 #include <iostream>
50 #include <list>
51 #include <string>
52 #include <vector>
53 
54 namespace TCLAP {
55 
56 class StandaloneArgs : public AnyOf {
57 public:
59 
60  ArgContainer &add(Arg *arg) {
61  // std::cerr << "Adding " << arg->getName() << " to StandaloneArgs\n";
62  for (iterator it = begin(); it != end(); it++) {
63  if (*arg == **it) {
65  "Argument with same flag/name already exists!",
66  arg->longID());
67  }
68  }
69 
70  _args.push_back(arg);
71 
72  return *this;
73  }
74 
75  bool showAsGroup() const { return false; }
76 };
77 
82 class CmdLine : public CmdLineInterface {
83 protected:
88  std::list<Arg *> _argList;
89 
91  StandaloneArgs _autoArgs; // --help, --version, etc
92 
97  std::list<ArgGroup *> _argGroups;
98 
102  std::string _progName;
103 
107  std::string _message;
108 
112  std::string _version;
113 
120 
126 
133 
138 
143 
148 
152  void missingArgsException(const std::list<ArgGroup *> &missing);
153 
160  bool _emptyCombined(const std::string &s);
161 
162 private:
166  CmdLine(const CmdLine &rhs);
167  CmdLine &operator=(const CmdLine &rhs);
168 
173  void _constructor();
174 
178  bool _helpAndVersion;
179 
183  bool _ignoreUnmatched;
184 
188  bool _ignoring;
189 
190 public:
203  CmdLine(const std::string &message, const char delimiter = ' ',
204  const std::string &version = "none", bool helpAndVersion = true);
205 
209  virtual ~CmdLine() {}
210 
217  ArgContainer &add(Arg &a);
218 
225  ArgContainer &add(Arg *a);
226 
237  ArgContainer &add(ArgGroup &args);
238 
239  // Internal, do not use
240  void addToArgList(Arg *a);
241 
245  void xorAdd(Arg &a, Arg &b);
246 
250  void xorAdd(const std::vector<Arg *> &xors);
251 
257  void parse(int argc, const char *const *argv);
258 
264  void parse(std::vector<std::string> &args);
265 
266  void setOutput(CmdLineOutput *co);
267 
268  std::string getVersion() const { return _version; }
269 
270  std::string getProgramName() const { return _progName; }
271 
272  // TOOD: Get rid of getArgList
273  std::list<Arg *> getArgList() const { return _argList; }
274  std::list<ArgGroup *> getArgGroups() {
275  std::list<ArgGroup *> groups = _argGroups;
276  groups.push_back(&_autoArgs);
277  return groups;
278  }
279 
280  char getDelimiter() const { return _delimiter; }
281  std::string getMessage() const { return _message; }
282  bool hasHelpAndVersion() const { return _helpAndVersion; }
283 
289  void setExceptionHandling(const bool state);
290 
297  bool hasExceptionHandling() const { return _handleExceptions; }
298 
302  void reset();
303 
310  void ignoreUnmatched(const bool ignore);
311 
312  void beginIgnoring() { _ignoring = true; }
313  bool ignoreRest() { return _ignoring; }
314 };
315 
317 // Begin CmdLine.cpp
319 
320 inline CmdLine::CmdLine(const std::string &m, char delim, const std::string &v,
321  bool help)
322  : _argList(),
323  _standaloneArgs(),
324  _autoArgs(),
325  _argGroups(),
326  _progName("not_set_yet"),
327  _message(m),
328  _version(v),
329  _numRequired(0),
330  _delimiter(delim),
331  _deleteOnExit(),
332  _defaultOutput(),
333  _output(&_defaultOutput),
334  _handleExceptions(true),
335  _helpAndVersion(help),
336  _ignoreUnmatched(false),
337  _ignoring(false) {
338  _constructor();
339 }
340 
341 inline void CmdLine::_constructor() {
343 
344  Visitor *v;
346  _autoArgs.setParser(*this);
347  // add(_autoArgs);
348 
349  v = new IgnoreRestVisitor(*this);
350  SwitchArg *ignore = new SwitchArg(
352  "Ignores the rest of the labeled arguments following this flag.", false,
353  v);
354  _deleteOnExit(ignore);
355  _deleteOnExit(v);
356  _autoArgs.add(ignore);
357  addToArgList(ignore);
358 
359  if (_helpAndVersion) {
360  v = new HelpVisitor(this, &_output);
361  SwitchArg *help = new SwitchArg(
362  "h", "help", "Displays usage information and exits.", false, v);
363  _deleteOnExit(help);
364  _deleteOnExit(v);
365 
366  v = new VersionVisitor(this, &_output);
367  SwitchArg *vers = new SwitchArg(
368  "", "version", "Displays version information and exits.", false, v);
369  _deleteOnExit(vers);
370  _deleteOnExit(v);
371 
372  // A bit of a hack on the order to make tests easier to fix,
373  // to be reverted
374  _autoArgs.add(vers);
375  addToArgList(vers);
376  _autoArgs.add(help);
377  addToArgList(help);
378  }
379 }
380 
381 inline void CmdLine::xorAdd(const std::vector<Arg *> &args) {
382  OneOf *group = new OneOf(*this);
383  _deleteOnExit(group);
384 
385  for (std::vector<Arg *>::const_iterator it = args.begin(); it != args.end();
386  ++it) {
387  group->add(**it);
388  }
389 }
390 
391 inline void CmdLine::xorAdd(Arg &a, Arg &b) {
392  std::vector<Arg *> ors;
393  ors.push_back(&a);
394  ors.push_back(&b);
395  xorAdd(ors);
396 }
397 
399  args.setParser(*this);
400  _argGroups.push_back(&args);
401 
402  return *this;
403 }
404 
405 inline ArgContainer &CmdLine::add(Arg &a) { return add(&a); }
406 
407 // TODO: Rename this to something smarter or refactor this logic so
408 // it's not needed.
409 inline void CmdLine::addToArgList(Arg *a) {
410  for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
411  if (*a == *(*it))
413  "Argument with same flag/name already exists!", a->longID()));
414 
415  a->addToList(_argList);
416 
417  if (a->isRequired()) _numRequired++;
418 }
419 
421  addToArgList(a);
422  _standaloneArgs.add(a);
423 
424  return *this;
425 }
426 
427 inline void CmdLine::parse(int argc, const char *const *argv) {
428  // this step is necessary so that we have easy access to
429  // mutable strings.
430  std::vector<std::string> args;
431  for (int i = 0; i < argc; i++) args.push_back(argv[i]);
432 
433  parse(args);
434 }
435 
436 inline void CmdLine::parse(std::vector<std::string> &args) {
437  bool shouldExit = false;
438  int estat = 0;
439 
440  try {
441  if (args.empty()) {
442  // https://sourceforge.net/p/tclap/bugs/30/
443  throw CmdLineParseException(
444  "The args vector must not be empty, "
445  "the first entry should contain the "
446  "program's name.");
447  }
448 
449  // TODO(macbishop): Maybe store the full name somewhere?
450  _progName = basename(args.front());
451  args.erase(args.begin());
452 
453  int requiredCount = 0;
454  std::list<ArgGroup *> missingArgGroups;
455 
456  // Check that the right amount of arguments are provided for
457  // each ArgGroup, and if there are any required arguments
458  // missing, store them for later. Other errors will cause an
459  // exception to be thrown and parse will exit early.
460  /*
461  for (std::list<ArgGroup*>::iterator it = _argGroups.begin();
462  it != _argGroups.end(); ++it) {
463  bool missingRequired = (*it)->validate(args);
464  if (missingRequired) {
465  missingArgGroups.push_back(*it);
466  }
467  }
468  */
469 
470  for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) {
471  bool matched = false;
472  for (ArgListIterator it = _argList.begin(); it != _argList.end();
473  it++) {
474  Arg &arg = **it;
475  // We check if the argument was already set (e.g., for
476  // a Multi-Arg) since then we don't want to count it
477  // as required again. This is a hack/workaround to
478  // make isRequired() imutable so it can be used to
479  // display help correctly (also it's a good idea).
480  //
481  // TODO: This logic should probably be refactored to
482  // remove this logic from here.
483  bool alreadySet = arg.isSet();
484  bool ignore = arg.isIgnoreable() && ignoreRest();
485  if (!ignore && arg.processArg(&i, args)) {
486  requiredCount += (!alreadySet && arg.isRequired()) ? 1 : 0;
487  matched = true;
488  break;
489  }
490  }
491 
492  // checks to see if the argument is an empty combined
493  // switch and if so, then we've actually matched it
494  if (!matched && _emptyCombined(args[i])) matched = true;
495 
496  if (!matched && !ignoreRest() && !_ignoreUnmatched)
497  throw(
498  CmdLineParseException("Couldn't find match "
499  "for argument",
500  args[i]));
501  }
502 
503  // Once all arguments have been parsed, check that we don't
504  // violate any constraints.
505  for (std::list<ArgGroup *>::iterator it = _argGroups.begin();
506  it != _argGroups.end(); ++it) {
507  bool missingRequired = (*it)->validate();
508  if (missingRequired) {
509  missingArgGroups.push_back(*it);
510  }
511  }
512 
513  if (requiredCount < _numRequired || !missingArgGroups.empty()) {
514  missingArgsException(missingArgGroups);
515  }
516 
517  if (requiredCount > _numRequired) {
518  throw(CmdLineParseException("Too many arguments!"));
519  }
520  } catch (ArgException &e) {
521  // If we're not handling the exceptions, rethrow.
522  if (!_handleExceptions) {
523  throw;
524  }
525 
526  try {
527  _output->failure(*this, e);
528  } catch (ExitException &ee) {
529  estat = ee.getExitStatus();
530  shouldExit = true;
531  }
532  } catch (ExitException &ee) {
533  // If we're not handling the exceptions, rethrow.
534  if (!_handleExceptions) {
535  throw;
536  }
537 
538  estat = ee.getExitStatus();
539  shouldExit = true;
540  }
541 
542  if (shouldExit) exit(estat);
543 }
544 
545 inline bool CmdLine::_emptyCombined(const std::string &s) {
546  if (s.length() > 0 && s[0] != Arg::flagStartChar()) return false;
547 
548  for (int i = 1; static_cast<unsigned int>(i) < s.length(); i++)
549  if (s[i] != Arg::blankChar()) return false;
550 
551  return true;
552 }
553 
555  const std::list<ArgGroup *> &missing) {
556  int count = 0;
557 
558  std::string missingArgList;
559  for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) {
560  if ((*it)->isRequired() && !(*it)->isSet()) {
561  missingArgList += (*it)->getName();
562  missingArgList += ", ";
563  count++;
564  }
565  }
566 
567  for (std::list<ArgGroup *>::const_iterator it = missing.begin();
568  it != missing.end(); it++) {
569  missingArgList += (*it)->getName();
570  missingArgList += ", ";
571  count++;
572  }
573 
574  missingArgList = missingArgList.substr(0, missingArgList.length() - 2);
575 
576  std::string msg;
577  if (count > 1)
578  msg = "Required arguments missing: ";
579  else
580  msg = "Required argument missing: ";
581 
582  msg += missingArgList;
583 
584  throw(CmdLineParseException(msg));
585 }
586 
587 inline void CmdLine::setOutput(CmdLineOutput *co) { _output = co; }
588 
589 inline void CmdLine::setExceptionHandling(const bool state) {
590  _handleExceptions = state;
591 }
592 
593 inline void CmdLine::reset() {
594  // TODO: This is no longer correct (or perhaps we don't need "reset")
595  for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
596  (*it)->reset();
597 
598  _progName.clear();
599 }
600 
601 inline void CmdLine::ignoreUnmatched(const bool ignore) {
602  _ignoreUnmatched = ignore;
603 }
604 
606 // End CmdLine.cpp
608 
609 } // namespace TCLAP
610 
611 #endif // TCLAP_CMD_LINE_H
bool hasExceptionHandling() const
Returns the current state of the internal exception handling.
Definition: CmdLine.h:297
std::list< Arg * > _argList
The list of arguments that will be tested against the command line.
Definition: CmdLine.h:88
StandaloneArgs _autoArgs
Definition: CmdLine.h:91
Implements a group of arguments where exactly one must be selected.
Definition: ArgGroup.h:168
CmdLineOutput * _output
Object that handles all output for the CmdLine.
Definition: CmdLine.h:142
void setParser(CmdLineInterface &parser)
Used by the parser to connect itself to this arg group.
Definition: ArgGroup.h:90
A virtual base class that defines the essential data for all arguments.
Definition: Arg.h:53
std::string _message
A message used to describe the program.
Definition: CmdLine.h:107
void xorAdd(Arg &a, Arg &b)
Definition: CmdLine.h:391
iterator begin()
Definition: ArgGroup.h:109
A simple class that defines and argument exception.
Definition: ArgException.h:36
virtual void failure(CmdLineInterface &c, ArgException &e)=0
Generates some sort of output for a failure.
ArgContainer & add(Arg *arg)
Add an argument to this arg group.
Definition: CmdLine.h:60
void beginIgnoring()
Begin ignoring arguments since the "--" argument was specified.
Definition: CmdLine.h:312
virtual void addToList(std::list< Arg *> &argList) const
Adds this to the specified list of Args.
Definition: Arg.h:587
std::string _progName
The name of the program.
Definition: CmdLine.h:102
Thrown from CmdLine when the arguments on the command line are not properly specified, e.g.
Definition: ArgException.h:129
static char flagStartChar()
Definition: Arg.h:201
bool ignoreRest()
Whether to ignore the rest.
Definition: CmdLine.h:313
std::string _version
The version to be displayed with the –version switch.
Definition: CmdLine.h:112
Thrown when TCLAP thinks the program should exit.
Definition: ArgException.h:178
A simple switch argument.
Definition: SwitchArg.h:40
virtual ~CmdLine()
Deletes any resources allocated by a CmdLine object.
Definition: CmdLine.h:209
bool isSet() const
Indicates whether the argument has already been set.
Definition: Arg.h:531
bool hasHelpAndVersion() const
Indicates whether or not the help and version switches were created automatically.
Definition: CmdLine.h:282
Thrown from Arg and CmdLine when an Arg is improperly specified, e.g.
Definition: ArgException.h:150
virtual std::string longID(const std::string &valueId="val") const
Returns a long ID for the usage.
Definition: Arg.h:498
StdOutput _defaultOutput
Default output handler if nothing is specified.
Definition: CmdLine.h:137
ArgContainer & add(Arg &a)
Adds an argument to the list of arguments to be parsed.
Definition: CmdLine.h:405
void reset()
Allows the CmdLine object to be reused.
Definition: CmdLine.h:593
char getDelimiter() const
Returns the delimiter string.
Definition: CmdLine.h:280
virtual bool isRequired() const
Indicates whether the argument is required.
Definition: Arg.h:527
char _delimiter
The character that is used to separate the argument flag/name from the value.
Definition: CmdLine.h:125
DeferDelete can be used by objects that need to allocate arbitrary other objects to live for the dura...
Definition: DeferDelete.h:34
A Visitor that will call the version method of the given CmdLineOutput for the specified CmdLine obje...
std::string getVersion() const
Returns the version string.
Definition: CmdLine.h:268
static const std::string ignoreNameString()
The name used to identify the ignore rest argument.
Definition: Arg.h:225
std::string getMessage() const
Returns the message string.
Definition: CmdLine.h:281
Interface that allows adding an Arg to a "container".
Definition: ArgContainer.h:39
int _numRequired
The number of arguments that are required to be present on the command line.
Definition: CmdLine.h:119
std::string getProgramName() const
Returns the program name string.
Definition: CmdLine.h:270
bool _emptyCombined(const std::string &s)
Checks whether a name/flag string matches entirely matches the Arg::blankChar.
Definition: CmdLine.h:545
Container::iterator iterator
Definition: ArgGroup.h:44
A base class that defines the interface for visitors.
Definition: Visitor.h:32
DeferDelete _deleteOnExit
Add pointers that should be deleted as part of cleanup when this object is destroyed.
Definition: CmdLine.h:132
ArgContainer & add(Arg &arg)
Add an argument to this arg group.
Definition: ArgGroup.h:136
std::string basename(std::string s)
Definition: CmdLineOutput.h:94
The base class that manages the command line definition and passes along the parsing to the appropria...
void missingArgsException(const std::list< ArgGroup *> &missing)
Throws an exception listing the missing args.
Definition: CmdLine.h:554
void setExceptionHandling(const bool state)
Disables or enables CmdLine&#39;s internal parsing exception handling.
Definition: CmdLine.h:589
std::list< ArgGroup * > _argGroups
Some args have set constraints on them (i.e., exactly or at most one must be specified.
Definition: CmdLine.h:97
virtual bool processArg(int *i, std::vector< std::string > &args)=0
Pure virtual method meant to handle the parsing and value assignment of the string on the command lin...
A class that isolates any output from the CmdLine object so that it may be easily modified...
Definition: StdOutput.h:46
StandaloneArgs _standaloneArgs
Definition: CmdLine.h:90
std::list< ArgGroup * > getArgGroups()
Returns the list of ArgGroups.
Definition: CmdLine.h:274
A Visitor object that calls the usage method of the given CmdLineOutput object for the specified CmdL...
Definition: HelpVisitor.h:36
void parse(int argc, const char *const *argv)
Parses the command line.
Definition: CmdLine.h:427
Container _args
Definition: ArgGroup.h:124
bool isIgnoreable() const
Indicates whether the argument can be ignored, if desired.
Definition: Arg.h:533
A Visitor that tells the CmdLine to begin ignoring arguments after this one is parsed.
void ignoreUnmatched(const bool ignore)
Allows unmatched args to be ignored.
Definition: CmdLine.h:601
int getExitStatus() const
Definition: ArgException.h:182
void setOutput(CmdLineOutput *co)
Definition: CmdLine.h:587
static char blankChar()
The char used as a place holder when SwitchArgs are combined.
Definition: Arg.h:192
Implements a group of arguments where any combination is possible (including all or none)...
Definition: ArgGroup.h:182
std::list< Arg * > getArgList() const
Definition: CmdLine.h:273
std::list< Arg * >::const_iterator ArgListIterator
Typedef of an Arg list iterator.
Definition: Arg.h:380
Definition: Arg.h:46
ArgGroup is the base class for implementing groups of arguments that are mutually exclusive (it repla...
Definition: ArgGroup.h:41
The base class that manages the command line definition and passes along the parsing to the appropria...
Definition: CmdLine.h:82
iterator end()
Definition: ArgGroup.h:110
bool _handleExceptions
Should CmdLine handle parsing exceptions internally?
Definition: CmdLine.h:147
bool showAsGroup() const
If arguments in this group should show up as grouped in help.
Definition: CmdLine.h:75
static const std::string flagStartString()
Definition: Arg.h:211
void addToArgList(Arg *a)
Definition: CmdLine.h:409
static void setDelimiter(char c)
Sets the delimiter for all arguments.
Definition: Arg.h:231
The interface that any output object must implement.
Definition: CmdLineOutput.h:45