You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

CmdLine.h 18 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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. {
  45. template<typename T>
  46. void DelPtr(T ptr)
  47. {
  48. delete ptr;
  49. }
  50. template<typename C>
  51. void ClearContainer(C& c)
  52. {
  53. typedef typename C::value_type value_type;
  54. std::for_each(c.begin(), c.end(), DelPtr<value_type>);
  55. c.clear();
  56. }
  57. /**
  58. * The base class that manages the command line definition and passes
  59. * along the parsing to the appropriate Arg classes.
  60. */
  61. class CmdLine : public CmdLineInterface
  62. {
  63. protected:
  64. /**
  65. * The list of arguments that will be tested against the
  66. * command line.
  67. */
  68. std::list<Arg*> _argList;
  69. /**
  70. * The name of the program. Set to argv[0].
  71. */
  72. std::string _progName;
  73. /**
  74. * A message used to describe the program. Used in the usage output.
  75. */
  76. std::string _message;
  77. /**
  78. * The version to be displayed with the --version switch.
  79. */
  80. std::string _version;
  81. /**
  82. * The number of arguments that are required to be present on
  83. * the command line. This is set dynamically, based on the
  84. * Args added to the CmdLine object.
  85. */
  86. int _numRequired;
  87. /**
  88. * The character that is used to separate the argument flag/name
  89. * from the value. Defaults to ' ' (space).
  90. */
  91. char _delimiter;
  92. /**
  93. * The handler that manages xoring lists of args.
  94. */
  95. XorHandler _xorHandler;
  96. /**
  97. * A list of Args to be explicitly deleted when the destructor
  98. * is called. At the moment, this only includes the three default
  99. * Args.
  100. */
  101. std::list<Arg*> _argDeleteOnExitList;
  102. /**
  103. * A list of Visitors to be explicitly deleted when the destructor
  104. * is called. At the moment, these are the Visitors created for the
  105. * default Args.
  106. */
  107. std::list<Visitor*> _visitorDeleteOnExitList;
  108. /**
  109. * Object that handles all output for the CmdLine.
  110. */
  111. CmdLineOutput* _output;
  112. /**
  113. * Should CmdLine handle parsing exceptions internally?
  114. */
  115. bool _handleExceptions;
  116. /**
  117. * Throws an exception listing the missing args.
  118. */
  119. void missingArgsException();
  120. /**
  121. * Checks whether a name/flag string matches entirely matches
  122. * the Arg::blankChar. Used when multiple switches are combined
  123. * into a single argument.
  124. * \param s - The message to be used in the usage.
  125. */
  126. bool _emptyCombined(const std::string& s);
  127. /**
  128. * Perform a delete ptr; operation on ptr when this object is deleted.
  129. */
  130. void deleteOnExit(Arg* ptr);
  131. /**
  132. * Perform a delete ptr; operation on ptr when this object is deleted.
  133. */
  134. void deleteOnExit(Visitor* ptr);
  135. private:
  136. /**
  137. * Prevent accidental copying.
  138. */
  139. CmdLine(const CmdLine& rhs);
  140. CmdLine& operator=(const CmdLine& rhs);
  141. /**
  142. * Encapsulates the code common to the constructors
  143. * (which is all of it).
  144. */
  145. void _constructor();
  146. /**
  147. * Is set to true when a user sets the output object. We use this so
  148. * that we don't delete objects that are created outside of this lib.
  149. */
  150. bool _userSetOutput;
  151. /**
  152. * Whether or not to automatically create help and version switches.
  153. */
  154. bool _helpAndVersion;
  155. /**
  156. * Whether or not to ignore unmatched args.
  157. */
  158. bool _ignoreUnmatched;
  159. public:
  160. /**
  161. * Command line constructor. Defines how the arguments will be
  162. * parsed.
  163. * \param message - The message to be used in the usage
  164. * output.
  165. * \param delimiter - The character that is used to separate
  166. * the argument flag/name from the value. Defaults to ' ' (space).
  167. * \param version - The version number to be used in the
  168. * --version switch.
  169. * \param helpAndVersion - Whether or not to create the Help and
  170. * Version switches. Defaults to true.
  171. */
  172. CmdLine(const std::string& message, const char delimiter = ' ', const std::string& version = "none", 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, char delim, const std::string& v, bool help) :
  277. _argList(std::list<Arg*>()),
  278. _progName("not_set_yet"),
  279. _message(m),
  280. _version(v),
  281. _numRequired(0),
  282. _delimiter(delim),
  283. _xorHandler(XorHandler()),
  284. _argDeleteOnExitList(std::list<Arg*>()),
  285. _visitorDeleteOnExitList(std::list<Visitor*>()),
  286. _output(0),
  287. _handleExceptions(true),
  288. _userSetOutput(false),
  289. _helpAndVersion(help),
  290. _ignoreUnmatched(false)
  291. {
  292. _constructor();
  293. }
  294. inline CmdLine::~CmdLine()
  295. {
  296. ClearContainer(_argDeleteOnExitList);
  297. ClearContainer(_visitorDeleteOnExitList);
  298. if (!_userSetOutput)
  299. {
  300. delete _output;
  301. _output = 0;
  302. }
  303. }
  304. inline void CmdLine::_constructor()
  305. {
  306. _output = new StdOutput;
  307. Arg::setDelimiter(_delimiter);
  308. Visitor* v;
  309. if (_helpAndVersion)
  310. {
  311. v = new HelpVisitor(this, &_output);
  312. SwitchArg* help = new SwitchArg("h", "help", "Displays usage information and exits.", false, v);
  313. add(help);
  314. deleteOnExit(help);
  315. deleteOnExit(v);
  316. v = new VersionVisitor(this, &_output);
  317. SwitchArg* vers = new SwitchArg("", "version", "Displays version information and exits.", false, v);
  318. add(vers);
  319. deleteOnExit(vers);
  320. deleteOnExit(v);
  321. }
  322. v = new IgnoreRestVisitor();
  323. SwitchArg* ignore = new SwitchArg(Arg::flagStartString(), Arg::ignoreNameString(), "Ignores the rest of the labeled arguments following this flag.", false, v);
  324. add(ignore);
  325. deleteOnExit(ignore);
  326. deleteOnExit(v);
  327. }
  328. inline void CmdLine::xorAdd(const std::vector<Arg*>& ors)
  329. {
  330. _xorHandler.add(ors);
  331. for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
  332. {
  333. (*it)->forceRequired();
  334. (*it)->setRequireLabel("OR required");
  335. add(*it);
  336. }
  337. }
  338. inline void CmdLine::xorAdd(Arg& a, Arg& b)
  339. {
  340. std::vector<Arg*> ors;
  341. ors.push_back(&a);
  342. ors.push_back(&b);
  343. xorAdd(ors);
  344. }
  345. inline void CmdLine::add(Arg& a)
  346. {
  347. add(&a);
  348. }
  349. inline void CmdLine::add(Arg* a)
  350. {
  351. for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
  352. if (*a == *(*it))
  353. throw(SpecificationException(
  354. "Argument with same flag/name already exists!",
  355. a->longID()
  356. ));
  357. a->addToList(_argList);
  358. if (a->isRequired())
  359. _numRequired++;
  360. }
  361. inline void CmdLine::parse(int argc, const char* const* argv)
  362. {
  363. // this step is necessary so that we have easy access to
  364. // mutable strings.
  365. std::vector<std::string> args;
  366. for (int i = 0; i < argc; i++)
  367. args.push_back(argv[i]);
  368. parse(args);
  369. }
  370. inline void CmdLine::parse(std::vector<std::string>& args)
  371. {
  372. bool shouldExit = false;
  373. int estat = 0;
  374. try
  375. {
  376. if (args.empty())
  377. {
  378. // https://sourceforge.net/p/tclap/bugs/30/
  379. throw CmdLineParseException("The args vector must not be empty, "
  380. "the first entry should contain the "
  381. "program's name.");
  382. }
  383. _progName = args.front();
  384. args.erase(args.begin());
  385. int requiredCount = 0;
  386. for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
  387. {
  388. bool matched = false;
  389. for (ArgListIterator it = _argList.begin();
  390. it != _argList.end();
  391. it++)
  392. {
  393. if ((*it)->processArg(&i, args))
  394. {
  395. requiredCount += _xorHandler.check(*it);
  396. matched = true;
  397. break;
  398. }
  399. }
  400. // checks to see if the argument is an empty combined
  401. // switch and if so, then we've actually matched it
  402. if (!matched && _emptyCombined(args[i]))
  403. matched = true;
  404. if (!matched && !Arg::ignoreRest() && !_ignoreUnmatched)
  405. throw(CmdLineParseException("Couldn't find match "
  406. "for argument",
  407. args[i]));
  408. }
  409. if (requiredCount < _numRequired)
  410. missingArgsException();
  411. if (requiredCount > _numRequired)
  412. throw(CmdLineParseException("Too many arguments!"));
  413. }
  414. catch (ArgException& e)
  415. {
  416. // If we're not handling the exceptions, rethrow.
  417. if (!_handleExceptions)
  418. {
  419. throw;
  420. }
  421. try
  422. {
  423. _output->failure(*this, e);
  424. }
  425. catch (ExitException& ee)
  426. {
  427. estat = ee.getExitStatus();
  428. shouldExit = true;
  429. }
  430. }
  431. catch (ExitException& ee)
  432. {
  433. // If we're not handling the exceptions, rethrow.
  434. if (!_handleExceptions)
  435. {
  436. throw;
  437. }
  438. estat = ee.getExitStatus();
  439. shouldExit = true;
  440. }
  441. if (shouldExit)
  442. exit(estat);
  443. }
  444. inline bool CmdLine::_emptyCombined(const std::string& s)
  445. {
  446. if (s.length() > 0 && s[0] != Arg::flagStartChar())
  447. return false;
  448. for (int i = 1; static_cast<unsigned int>(i) < s.length(); i++)
  449. if (s[i] != Arg::blankChar())
  450. return false;
  451. return true;
  452. }
  453. inline void CmdLine::missingArgsException()
  454. {
  455. int count = 0;
  456. std::string missingArgList;
  457. for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
  458. {
  459. if ((*it)->isRequired() && !(*it)->isSet())
  460. {
  461. missingArgList += (*it)->getName();
  462. missingArgList += ", ";
  463. count++;
  464. }
  465. }
  466. missingArgList = missingArgList.substr(0, missingArgList.length() - 2);
  467. std::string msg;
  468. if (count > 1)
  469. msg = "Required arguments missing: ";
  470. else
  471. msg = "Required argument missing: ";
  472. msg += missingArgList;
  473. throw(CmdLineParseException(msg));
  474. }
  475. inline void CmdLine::deleteOnExit(Arg* ptr)
  476. {
  477. _argDeleteOnExitList.push_back(ptr);
  478. }
  479. inline void CmdLine::deleteOnExit(Visitor* ptr)
  480. {
  481. _visitorDeleteOnExitList.push_back(ptr);
  482. }
  483. inline CmdLineOutput* CmdLine::getOutput()
  484. {
  485. return _output;
  486. }
  487. inline void CmdLine::setOutput(CmdLineOutput* co)
  488. {
  489. if (!_userSetOutput)
  490. delete _output;
  491. _userSetOutput = true;
  492. _output = co;
  493. }
  494. inline std::string& CmdLine::getVersion()
  495. {
  496. return _version;
  497. }
  498. inline std::string& CmdLine::getProgramName()
  499. {
  500. return _progName;
  501. }
  502. inline std::list<Arg*>& CmdLine::getArgList()
  503. {
  504. return _argList;
  505. }
  506. inline XorHandler& CmdLine::getXorHandler()
  507. {
  508. return _xorHandler;
  509. }
  510. inline char CmdLine::getDelimiter()
  511. {
  512. return _delimiter;
  513. }
  514. inline std::string& CmdLine::getMessage()
  515. {
  516. return _message;
  517. }
  518. inline bool CmdLine::hasHelpAndVersion()
  519. {
  520. return _helpAndVersion;
  521. }
  522. inline void CmdLine::setExceptionHandling(const bool state)
  523. {
  524. _handleExceptions = state;
  525. }
  526. inline bool CmdLine::getExceptionHandling() const
  527. {
  528. return _handleExceptions;
  529. }
  530. inline void CmdLine::reset()
  531. {
  532. for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
  533. (*it)->reset();
  534. _progName.clear();
  535. }
  536. inline void CmdLine::ignoreUnmatched(const bool ignore)
  537. {
  538. _ignoreUnmatched = ignore;
  539. }
  540. ///////////////////////////////////////////////////////////////////////////////
  541. // End CmdLine.cpp
  542. ///////////////////////////////////////////////////////////////////////////////
  543. } // namespace TCLAP
  544. #endif