CmdLine.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
  2. /******************************************************************************
  3. *
  4. * file: CmdLine.h
  5. *
  6. * Copyright (c) 2003, Michael E. Smoot .
  7. * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
  8. * All rights reserved.
  9. *
  10. * See the file COPYING in the top directory of this distribution for
  11. * more information.
  12. *
  13. * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
  14. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  16. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19. * DEALINGS IN THE SOFTWARE.
  20. *
  21. *****************************************************************************/
  22. #ifndef TCLAP_CMDLINE_H
  23. #define TCLAP_CMDLINE_H
  24. #include <tclap/SwitchArg.h>
  25. #include <tclap/MultiSwitchArg.h>
  26. #include <tclap/UnlabeledValueArg.h>
  27. #include <tclap/UnlabeledMultiArg.h>
  28. #include <tclap/XorHandler.h>
  29. #include <tclap/HelpVisitor.h>
  30. #include <tclap/VersionVisitor.h>
  31. #include <tclap/IgnoreRestVisitor.h>
  32. #include <tclap/CmdLineOutput.h>
  33. #include <tclap/StdOutput.h>
  34. #include <tclap/Constraint.h>
  35. #include <tclap/ValuesConstraint.h>
  36. #include <string>
  37. #include <vector>
  38. #include <list>
  39. #include <iostream>
  40. #include <iomanip>
  41. #include <algorithm>
  42. #include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
  43. namespace TCLAP {
  44. template<typename T> void DelPtr(T ptr)
  45. {
  46. delete ptr;
  47. }
  48. template<typename C> void ClearContainer(C &c)
  49. {
  50. typedef typename C::value_type value_type;
  51. std::for_each(c.begin(), c.end(), DelPtr<value_type>);
  52. c.clear();
  53. }
  54. /**
  55. * The base class that manages the command line definition and passes
  56. * along the parsing to the appropriate Arg classes.
  57. */
  58. class CmdLine : public CmdLineInterface
  59. {
  60. protected:
  61. /**
  62. * The list of arguments that will be tested against the
  63. * command line.
  64. */
  65. std::list<Arg*> _argList;
  66. /**
  67. * The name of the program. Set to argv[0].
  68. */
  69. std::string _progName;
  70. /**
  71. * A message used to describe the program. Used in the usage output.
  72. */
  73. std::string _message;
  74. /**
  75. * The version to be displayed with the --version switch.
  76. */
  77. std::string _version;
  78. /**
  79. * The number of arguments that are required to be present on
  80. * the command line. This is set dynamically, based on the
  81. * Args added to the CmdLine object.
  82. */
  83. int _numRequired;
  84. /**
  85. * The character that is used to separate the argument flag/name
  86. * from the value. Defaults to ' ' (space).
  87. */
  88. char _delimiter;
  89. /**
  90. * The handler that manages xoring lists of args.
  91. */
  92. XorHandler _xorHandler;
  93. /**
  94. * A list of Args to be explicitly deleted when the destructor
  95. * is called. At the moment, this only includes the three default
  96. * Args.
  97. */
  98. std::list<Arg*> _argDeleteOnExitList;
  99. /**
  100. * A list of Visitors to be explicitly deleted when the destructor
  101. * is called. At the moment, these are the Visitors created for the
  102. * default Args.
  103. */
  104. std::list<Visitor*> _visitorDeleteOnExitList;
  105. /**
  106. * Object that handles all output for the CmdLine.
  107. */
  108. CmdLineOutput* _output;
  109. /**
  110. * Should CmdLine handle parsing exceptions internally?
  111. */
  112. bool _handleExceptions;
  113. /**
  114. * Throws an exception listing the missing args.
  115. */
  116. void missingArgsException();
  117. /**
  118. * Checks whether a name/flag string matches entirely matches
  119. * the Arg::blankChar. Used when multiple switches are combined
  120. * into a single argument.
  121. * \param s - The message to be used in the usage.
  122. */
  123. bool _emptyCombined(const std::string& s);
  124. /**
  125. * Perform a delete ptr; operation on ptr when this object is deleted.
  126. */
  127. void deleteOnExit(Arg* ptr);
  128. /**
  129. * Perform a delete ptr; operation on ptr when this object is deleted.
  130. */
  131. void deleteOnExit(Visitor* ptr);
  132. private:
  133. /**
  134. * Prevent accidental copying.
  135. */
  136. CmdLine(const CmdLine& rhs);
  137. CmdLine& operator=(const CmdLine& rhs);
  138. /**
  139. * Encapsulates the code common to the constructors
  140. * (which is all of it).
  141. */
  142. void _constructor();
  143. /**
  144. * Is set to true when a user sets the output object. We use this so
  145. * that we don't delete objects that are created outside of this lib.
  146. */
  147. bool _userSetOutput;
  148. /**
  149. * Whether or not to automatically create help and version switches.
  150. */
  151. bool _helpAndVersion;
  152. /**
  153. * Whether or not to ignore unmatched args.
  154. */
  155. bool _ignoreUnmatched;
  156. public:
  157. /**
  158. * Command line constructor. Defines how the arguments will be
  159. * parsed.
  160. * \param message - The message to be used in the usage
  161. * output.
  162. * \param delimiter - The character that is used to separate
  163. * the argument flag/name from the value. Defaults to ' ' (space).
  164. * \param version - The version number to be used in the
  165. * --version switch.
  166. * \param helpAndVersion - Whether or not to create the Help and
  167. * Version switches. Defaults to true.
  168. */
  169. CmdLine(const std::string& message,
  170. const char delimiter = ' ',
  171. const std::string& version = "none",
  172. bool helpAndVersion = true);
  173. /**
  174. * Deletes any resources allocated by a CmdLine object.
  175. */
  176. virtual ~CmdLine();
  177. /**
  178. * Adds an argument to the list of arguments to be parsed.
  179. * \param a - Argument to be added.
  180. */
  181. void add( Arg& a );
  182. /**
  183. * An alternative add. Functionally identical.
  184. * \param a - Argument to be added.
  185. */
  186. void add( Arg* a );
  187. /**
  188. * Add two Args that will be xor'd. If this method is used, add does
  189. * not need to be called.
  190. * \param a - Argument to be added and xor'd.
  191. * \param b - Argument to be added and xor'd.
  192. */
  193. void xorAdd( Arg& a, Arg& b );
  194. /**
  195. * Add a list of Args that will be xor'd. If this method is used,
  196. * add does not need to be called.
  197. * \param xors - List of Args to be added and xor'd.
  198. */
  199. void xorAdd( const std::vector<Arg*>& xors );
  200. /**
  201. * Parses the command line.
  202. * \param argc - Number of arguments.
  203. * \param argv - Array of arguments.
  204. */
  205. void parse(int argc, const char * const * argv);
  206. /**
  207. * Parses the command line.
  208. * \param args - A vector of strings representing the args.
  209. * args[0] is still the program name.
  210. */
  211. void parse(std::vector<std::string>& args);
  212. /**
  213. *
  214. */
  215. CmdLineOutput* getOutput();
  216. /**
  217. *
  218. */
  219. void setOutput(CmdLineOutput* co);
  220. /**
  221. *
  222. */
  223. std::string& getVersion();
  224. /**
  225. *
  226. */
  227. std::string& getProgramName();
  228. /**
  229. *
  230. */
  231. std::list<Arg*>& getArgList();
  232. /**
  233. *
  234. */
  235. XorHandler& getXorHandler();
  236. /**
  237. *
  238. */
  239. char getDelimiter();
  240. /**
  241. *
  242. */
  243. std::string& getMessage();
  244. /**
  245. *
  246. */
  247. bool hasHelpAndVersion();
  248. /**
  249. * Disables or enables CmdLine's internal parsing exception handling.
  250. *
  251. * @param state Should CmdLine handle parsing exceptions internally?
  252. */
  253. void setExceptionHandling(const bool state);
  254. /**
  255. * Returns the current state of the internal exception handling.
  256. *
  257. * @retval true Parsing exceptions are handled internally.
  258. * @retval false Parsing exceptions are propagated to the caller.
  259. */
  260. bool getExceptionHandling() const;
  261. /**
  262. * Allows the CmdLine object to be reused.
  263. */
  264. void reset();
  265. /**
  266. * Allows unmatched args to be ignored. By default false.
  267. *
  268. * @param ignore If true the cmdline will ignore any unmatched args
  269. * and if false it will behave as normal.
  270. */
  271. void ignoreUnmatched(const bool ignore);
  272. };
  273. ///////////////////////////////////////////////////////////////////////////////
  274. //Begin CmdLine.cpp
  275. ///////////////////////////////////////////////////////////////////////////////
  276. inline CmdLine::CmdLine(const std::string& m,
  277. char delim,
  278. const std::string& v,
  279. bool help )
  280. :
  281. _argList(std::list<Arg*>()),
  282. _progName("not_set_yet"),
  283. _message(m),
  284. _version(v),
  285. _numRequired(0),
  286. _delimiter(delim),
  287. _xorHandler(XorHandler()),
  288. _argDeleteOnExitList(std::list<Arg*>()),
  289. _visitorDeleteOnExitList(std::list<Visitor*>()),
  290. _output(0),
  291. _handleExceptions(true),
  292. _userSetOutput(false),
  293. _helpAndVersion(help),
  294. _ignoreUnmatched(false)
  295. {
  296. _constructor();
  297. }
  298. inline CmdLine::~CmdLine()
  299. {
  300. ClearContainer(_argDeleteOnExitList);
  301. ClearContainer(_visitorDeleteOnExitList);
  302. if ( !_userSetOutput ) {
  303. delete _output;
  304. _output = 0;
  305. }
  306. }
  307. inline void CmdLine::_constructor()
  308. {
  309. _output = new StdOutput;
  310. Arg::setDelimiter( _delimiter );
  311. Visitor* v;
  312. if ( _helpAndVersion )
  313. {
  314. v = new HelpVisitor( this, &_output );
  315. SwitchArg* help = new SwitchArg("h","help",
  316. "Displays usage information and exits.",
  317. false, v);
  318. add( help );
  319. deleteOnExit(help);
  320. deleteOnExit(v);
  321. v = new VersionVisitor( this, &_output );
  322. SwitchArg* vers = new SwitchArg("","version",
  323. "Displays version information and exits.",
  324. false, v);
  325. add( vers );
  326. deleteOnExit(vers);
  327. deleteOnExit(v);
  328. }
  329. v = new IgnoreRestVisitor();
  330. SwitchArg* ignore = new SwitchArg(Arg::flagStartString(),
  331. Arg::ignoreNameString(),
  332. "Ignores the rest of the labeled arguments following this flag.",
  333. false, v);
  334. add( ignore );
  335. deleteOnExit(ignore);
  336. deleteOnExit(v);
  337. }
  338. inline void CmdLine::xorAdd( const std::vector<Arg*>& ors )
  339. {
  340. _xorHandler.add( ors );
  341. for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
  342. {
  343. (*it)->forceRequired();
  344. (*it)->setRequireLabel( "OR required" );
  345. add( *it );
  346. }
  347. }
  348. inline void CmdLine::xorAdd( Arg& a, Arg& b )
  349. {
  350. std::vector<Arg*> ors;
  351. ors.push_back( &a );
  352. ors.push_back( &b );
  353. xorAdd( ors );
  354. }
  355. inline void CmdLine::add( Arg& a )
  356. {
  357. add( &a );
  358. }
  359. inline void CmdLine::add( Arg* a )
  360. {
  361. for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
  362. if ( *a == *(*it) )
  363. throw( SpecificationException(
  364. "Argument with same flag/name already exists!",
  365. a->longID() ) );
  366. a->addToList( _argList );
  367. if ( a->isRequired() )
  368. _numRequired++;
  369. }
  370. inline void CmdLine::parse(int argc, const char * const * argv)
  371. {
  372. // this step is necessary so that we have easy access to
  373. // mutable strings.
  374. std::vector<std::string> args;
  375. for (int i = 0; i < argc; i++)
  376. args.push_back(argv[i]);
  377. parse(args);
  378. }
  379. inline void CmdLine::parse(std::vector<std::string>& args)
  380. {
  381. bool shouldExit = false;
  382. int estat = 0;
  383. try {
  384. if (args.empty()) {
  385. // https://sourceforge.net/p/tclap/bugs/30/
  386. throw CmdLineParseException("The args vector must not be empty, "
  387. "the first entry should contain the "
  388. "program's name.");
  389. }
  390. _progName = args.front();
  391. args.erase(args.begin());
  392. int requiredCount = 0;
  393. for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
  394. {
  395. bool matched = false;
  396. for (ArgListIterator it = _argList.begin();
  397. it != _argList.end(); it++) {
  398. if ( (*it)->processArg( &i, args ) )
  399. {
  400. requiredCount += _xorHandler.check( *it );
  401. matched = true;
  402. break;
  403. }
  404. }
  405. // checks to see if the argument is an empty combined
  406. // switch and if so, then we've actually matched it
  407. if ( !matched && _emptyCombined( args[i] ) )
  408. matched = true;
  409. if ( !matched && !Arg::ignoreRest() && !_ignoreUnmatched)
  410. throw(CmdLineParseException("Couldn't find match "
  411. "for argument",
  412. args[i]));
  413. }
  414. if ( requiredCount < _numRequired )
  415. missingArgsException();
  416. if ( requiredCount > _numRequired )
  417. throw(CmdLineParseException("Too many arguments!"));
  418. } catch ( ArgException& e ) {
  419. // If we're not handling the exceptions, rethrow.
  420. if ( !_handleExceptions) {
  421. throw;
  422. }
  423. try {
  424. _output->failure(*this,e);
  425. } catch ( ExitException &ee ) {
  426. estat = ee.getExitStatus();
  427. shouldExit = true;
  428. }
  429. } catch (ExitException &ee) {
  430. // If we're not handling the exceptions, rethrow.
  431. if ( !_handleExceptions) {
  432. throw;
  433. }
  434. estat = ee.getExitStatus();
  435. shouldExit = true;
  436. }
  437. if (shouldExit)
  438. exit(estat);
  439. }
  440. inline bool CmdLine::_emptyCombined(const std::string& s)
  441. {
  442. if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
  443. return false;
  444. for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
  445. if ( s[i] != Arg::blankChar() )
  446. return false;
  447. return true;
  448. }
  449. inline void CmdLine::missingArgsException()
  450. {
  451. int count = 0;
  452. std::string missingArgList;
  453. for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
  454. {
  455. if ( (*it)->isRequired() && !(*it)->isSet() )
  456. {
  457. missingArgList += (*it)->getName();
  458. missingArgList += ", ";
  459. count++;
  460. }
  461. }
  462. missingArgList = missingArgList.substr(0,missingArgList.length()-2);
  463. std::string msg;
  464. if ( count > 1 )
  465. msg = "Required arguments missing: ";
  466. else
  467. msg = "Required argument missing: ";
  468. msg += missingArgList;
  469. throw(CmdLineParseException(msg));
  470. }
  471. inline void CmdLine::deleteOnExit(Arg* ptr)
  472. {
  473. _argDeleteOnExitList.push_back(ptr);
  474. }
  475. inline void CmdLine::deleteOnExit(Visitor* ptr)
  476. {
  477. _visitorDeleteOnExitList.push_back(ptr);
  478. }
  479. inline CmdLineOutput* CmdLine::getOutput()
  480. {
  481. return _output;
  482. }
  483. inline void CmdLine::setOutput(CmdLineOutput* co)
  484. {
  485. if ( !_userSetOutput )
  486. delete _output;
  487. _userSetOutput = true;
  488. _output = co;
  489. }
  490. inline std::string& CmdLine::getVersion()
  491. {
  492. return _version;
  493. }
  494. inline std::string& CmdLine::getProgramName()
  495. {
  496. return _progName;
  497. }
  498. inline std::list<Arg*>& CmdLine::getArgList()
  499. {
  500. return _argList;
  501. }
  502. inline XorHandler& CmdLine::getXorHandler()
  503. {
  504. return _xorHandler;
  505. }
  506. inline char CmdLine::getDelimiter()
  507. {
  508. return _delimiter;
  509. }
  510. inline std::string& CmdLine::getMessage()
  511. {
  512. return _message;
  513. }
  514. inline bool CmdLine::hasHelpAndVersion()
  515. {
  516. return _helpAndVersion;
  517. }
  518. inline void CmdLine::setExceptionHandling(const bool state)
  519. {
  520. _handleExceptions = state;
  521. }
  522. inline bool CmdLine::getExceptionHandling() const
  523. {
  524. return _handleExceptions;
  525. }
  526. inline void CmdLine::reset()
  527. {
  528. for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
  529. (*it)->reset();
  530. _progName.clear();
  531. }
  532. inline void CmdLine::ignoreUnmatched(const bool ignore)
  533. {
  534. _ignoreUnmatched = ignore;
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////
  537. //End CmdLine.cpp
  538. ///////////////////////////////////////////////////////////////////////////////
  539. } //namespace TCLAP
  540. #endif