ctkCommandLineParser.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // STL includes
  15. #include <stdexcept>
  16. // Qt includes
  17. #include <QHash>
  18. #include <QStringList>
  19. #include <QTextStream>
  20. #include <QDebug>
  21. #include <QSettings>
  22. #include <QPointer>
  23. // CTK includes
  24. #include "ctkCommandLineParser.h"
  25. namespace
  26. {
  27. // --------------------------------------------------------------------------
  28. class CommandLineParserArgumentDescription
  29. {
  30. public:
  31. CommandLineParserArgumentDescription(
  32. const QString& longArg, const QString& longArgPrefix,
  33. const QString& shortArg, const QString& shortArgPrefix,
  34. QVariant::Type type, const QString& argHelp,
  35. const QVariant& defaultValue, bool ignoreRest,
  36. bool deprecated)
  37. : LongArg(longArg), LongArgPrefix(longArgPrefix),
  38. ShortArg(shortArg), ShortArgPrefix(shortArgPrefix),
  39. ArgHelp(argHelp), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0),
  40. Deprecated(deprecated), DefaultValue(defaultValue), Value(type), ValueType(type)
  41. {
  42. if (defaultValue.isValid())
  43. {
  44. Value = defaultValue;
  45. }
  46. switch (type)
  47. {
  48. case QVariant::String:
  49. {
  50. NumberOfParametersToProcess = 1;
  51. RegularExpression = ".*";
  52. }
  53. break;
  54. case QVariant::Bool:
  55. {
  56. NumberOfParametersToProcess = 0;
  57. RegularExpression = "";
  58. }
  59. break;
  60. case QVariant::StringList:
  61. {
  62. NumberOfParametersToProcess = -1;
  63. RegularExpression = ".*";
  64. }
  65. break;
  66. case QVariant::Int:
  67. {
  68. NumberOfParametersToProcess = 1;
  69. RegularExpression = "-?[0-9]+";
  70. ExactMatchFailedMessage = "A negative or positive integer is expected.";
  71. }
  72. break;
  73. default:
  74. ExactMatchFailedMessage = QString("Type %1 not supported.").arg(static_cast<int>(type));
  75. }
  76. }
  77. ~CommandLineParserArgumentDescription(){}
  78. bool addParameter(const QString& value);
  79. QString helpText(int fieldWidth, const char charPad, const QString& settingsValue = "");
  80. QString LongArg;
  81. QString LongArgPrefix;
  82. QString ShortArg;
  83. QString ShortArgPrefix;
  84. QString ArgHelp;
  85. bool IgnoreRest;
  86. int NumberOfParametersToProcess;
  87. QString RegularExpression;
  88. QString ExactMatchFailedMessage;
  89. bool Deprecated;
  90. QVariant DefaultValue;
  91. QVariant Value;
  92. QVariant::Type ValueType;
  93. };
  94. // --------------------------------------------------------------------------
  95. bool CommandLineParserArgumentDescription::addParameter(const QString& value)
  96. {
  97. if (!RegularExpression.isEmpty())
  98. {
  99. // Validate value
  100. QRegExp regexp(this->RegularExpression);
  101. if (!regexp.exactMatch(value))
  102. {
  103. return false;
  104. }
  105. }
  106. switch (Value.type())
  107. {
  108. case QVariant::String:
  109. {
  110. Value.setValue(value);
  111. }
  112. break;
  113. case QVariant::Bool:
  114. {
  115. Value.setValue(!QString::compare(value, "true", Qt::CaseInsensitive));
  116. }
  117. break;
  118. case QVariant::StringList:
  119. {
  120. if (Value.isNull())
  121. {
  122. QStringList list;
  123. list << value;
  124. Value.setValue(list);
  125. }
  126. else
  127. {
  128. QStringList list = Value.toStringList();
  129. list << value;
  130. Value.setValue(list);
  131. }
  132. }
  133. break;
  134. case QVariant::Int:
  135. {
  136. Value.setValue(value.toInt());
  137. }
  138. break;
  139. default:
  140. return false;
  141. }
  142. return true;
  143. }
  144. // --------------------------------------------------------------------------
  145. QString CommandLineParserArgumentDescription::helpText(int fieldWidth, const char charPad,
  146. const QString& settingsValue)
  147. {
  148. QString text;
  149. QTextStream stream(&text);
  150. stream.setFieldAlignment(QTextStream::AlignLeft);
  151. stream.setPadChar(charPad);
  152. QString shortAndLongArg;
  153. if (!this->ShortArg.isEmpty())
  154. {
  155. shortAndLongArg += QString(" %1%2").arg(this->ShortArgPrefix).arg(this->ShortArg);
  156. }
  157. if (!this->LongArg.isEmpty())
  158. {
  159. if (this->ShortArg.isEmpty())
  160. {
  161. shortAndLongArg.append(" ");
  162. }
  163. else
  164. {
  165. shortAndLongArg.append(", ");
  166. }
  167. shortAndLongArg += QString("%1%2").arg(this->LongArgPrefix).arg(this->LongArg);
  168. }
  169. if(!this->ArgHelp.isEmpty())
  170. {
  171. stream.setFieldWidth(fieldWidth);
  172. }
  173. stream << shortAndLongArg;
  174. stream.setFieldWidth(0);
  175. stream << this->ArgHelp;
  176. if (!settingsValue.isNull())
  177. {
  178. stream << " (default: " << settingsValue << ")";
  179. }
  180. else if (!this->DefaultValue.isNull())
  181. {
  182. stream << " (default: " << this->DefaultValue.toString() << ")";
  183. }
  184. stream << "\n";
  185. return text;
  186. }
  187. }
  188. // --------------------------------------------------------------------------
  189. // ctkCommandLineParser::ctkInternal class
  190. // --------------------------------------------------------------------------
  191. class ctkCommandLineParser::ctkInternal
  192. {
  193. public:
  194. ctkInternal(QSettings* settings)
  195. : Debug(false), FieldWidth(0), UseQSettings(false),
  196. Settings(settings), MergeSettings(true), StrictMode(false)
  197. {}
  198. ~ctkInternal() { qDeleteAll(ArgumentDescriptionList); }
  199. CommandLineParserArgumentDescription* argumentDescription(const QString& argument);
  200. QList<CommandLineParserArgumentDescription*> ArgumentDescriptionList;
  201. QHash<QString, CommandLineParserArgumentDescription*> ArgNameToArgumentDescriptionMap;
  202. QMap<QString, QList<CommandLineParserArgumentDescription*> > GroupToArgumentDescriptionListMap;
  203. QStringList UnparsedArguments;
  204. QStringList ProcessedArguments;
  205. QString ErrorString;
  206. bool Debug;
  207. int FieldWidth;
  208. QString LongPrefix;
  209. QString ShortPrefix;
  210. QString CurrentGroup;
  211. bool UseQSettings;
  212. QPointer<QSettings> Settings;
  213. QString DisableQSettingsLongArg;
  214. QString DisableQSettingsShortArg;
  215. bool MergeSettings;
  216. bool StrictMode;
  217. };
  218. // --------------------------------------------------------------------------
  219. // ctkCommandLineParser::ctkInternal methods
  220. // --------------------------------------------------------------------------
  221. CommandLineParserArgumentDescription*
  222. ctkCommandLineParser::ctkInternal::argumentDescription(const QString& argument)
  223. {
  224. QString unprefixedArg = argument;
  225. if (!LongPrefix.isEmpty() && argument.startsWith(LongPrefix))
  226. {
  227. // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix
  228. if (argument == LongPrefix && !ShortPrefix.isEmpty() && argument.startsWith(ShortPrefix))
  229. {
  230. unprefixedArg = argument.mid(ShortPrefix.length());
  231. }
  232. else
  233. {
  234. unprefixedArg = argument.mid(LongPrefix.length());
  235. }
  236. }
  237. else if (!ShortPrefix.isEmpty() && argument.startsWith(ShortPrefix))
  238. {
  239. unprefixedArg = argument.mid(ShortPrefix.length());
  240. }
  241. else if (!LongPrefix.isEmpty() && !ShortPrefix.isEmpty())
  242. {
  243. return 0;
  244. }
  245. if (this->ArgNameToArgumentDescriptionMap.contains(unprefixedArg))
  246. {
  247. return this->ArgNameToArgumentDescriptionMap[unprefixedArg];
  248. }
  249. return 0;
  250. }
  251. // --------------------------------------------------------------------------
  252. // ctkCommandLineParser methods
  253. // --------------------------------------------------------------------------
  254. ctkCommandLineParser::ctkCommandLineParser(QObject* newParent) : Superclass(newParent)
  255. {
  256. this->Internal = new ctkInternal(0);
  257. }
  258. // --------------------------------------------------------------------------
  259. ctkCommandLineParser::ctkCommandLineParser(QSettings* settings, QObject* newParent) :
  260. Superclass(newParent)
  261. {
  262. this->Internal = new ctkInternal(settings);
  263. }
  264. // --------------------------------------------------------------------------
  265. ctkCommandLineParser::~ctkCommandLineParser()
  266. {
  267. delete this->Internal;
  268. }
  269. // --------------------------------------------------------------------------
  270. QHash<QString, QVariant> ctkCommandLineParser::parseArguments(const QStringList& arguments,
  271. bool* ok)
  272. {
  273. // Reset
  274. this->Internal->UnparsedArguments.clear();
  275. this->Internal->ProcessedArguments.clear();
  276. this->Internal->ErrorString.clear();
  277. foreach (CommandLineParserArgumentDescription* desc,
  278. this->Internal->ArgumentDescriptionList)
  279. {
  280. desc->Value = QVariant(desc->ValueType);
  281. if (desc->DefaultValue.isValid())
  282. {
  283. desc->Value = desc->DefaultValue;
  284. }
  285. }
  286. bool error = false;
  287. bool ignoreRest = false;
  288. bool useSettings = this->Internal->UseQSettings;
  289. CommandLineParserArgumentDescription * currentArgDesc = 0;
  290. QList<CommandLineParserArgumentDescription*> parsedArgDescriptions;
  291. for(int i = 1; i < arguments.size(); ++i)
  292. {
  293. QString argument = arguments.at(i);
  294. if (this->Internal->Debug) { qDebug() << "Processing" << argument; }
  295. // should argument be ignored ?
  296. if (ignoreRest)
  297. {
  298. if (this->Internal->Debug)
  299. {
  300. qDebug() << " Skipping: IgnoreRest flag was been set";
  301. }
  302. this->Internal->UnparsedArguments << argument;
  303. continue;
  304. }
  305. // Skip if the argument does not start with the defined prefix
  306. if (!(argument.startsWith(this->Internal->LongPrefix)
  307. || argument.startsWith(this->Internal->ShortPrefix)))
  308. {
  309. if (this->Internal->StrictMode)
  310. {
  311. this->Internal->ErrorString = QString("Unknown argument %1").arg(argument);
  312. error = true;
  313. break;
  314. }
  315. if (this->Internal->Debug)
  316. {
  317. qDebug() << " Skipping: It does not start with the defined prefix";
  318. }
  319. this->Internal->UnparsedArguments << argument;
  320. continue;
  321. }
  322. // Skip if argument has already been parsed ...
  323. if (this->Internal->ProcessedArguments.contains(argument))
  324. {
  325. if (this->Internal->StrictMode)
  326. {
  327. this->Internal->ErrorString = QString("Argument %1 already processed !").arg(argument);
  328. error = true;
  329. break;
  330. }
  331. if (this->Internal->Debug)
  332. {
  333. qDebug() << " Skipping: Already processed !";
  334. }
  335. continue;
  336. }
  337. // Retrieve corresponding argument description
  338. currentArgDesc = this->Internal->argumentDescription(argument);
  339. // Is there a corresponding argument description ?
  340. if (currentArgDesc)
  341. {
  342. // If the argument is deprecated, print the help text but continue processing
  343. if (currentArgDesc->Deprecated)
  344. {
  345. qWarning().nospace() << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp;
  346. }
  347. else
  348. {
  349. parsedArgDescriptions.push_back(currentArgDesc);
  350. }
  351. // Is the argument the special "disable QSettings" argument?
  352. if ((!currentArgDesc->LongArg.isEmpty() && currentArgDesc->LongArg == this->Internal->DisableQSettingsLongArg)
  353. || (!currentArgDesc->ShortArg.isEmpty() && currentArgDesc->ShortArg == this->Internal->DisableQSettingsShortArg))
  354. {
  355. useSettings = false;
  356. }
  357. this->Internal->ProcessedArguments << currentArgDesc->ShortArg << currentArgDesc->LongArg;
  358. int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess;
  359. ignoreRest = currentArgDesc->IgnoreRest;
  360. if (this->Internal->Debug && ignoreRest)
  361. {
  362. qDebug() << " IgnoreRest flag is True";
  363. }
  364. // Is the number of parameters associated with the argument being processed known ?
  365. if (numberOfParametersToProcess == 0)
  366. {
  367. currentArgDesc->addParameter("true");
  368. }
  369. else if (numberOfParametersToProcess > 0)
  370. {
  371. QString missingParameterError =
  372. "Argument %1 has %2 value(s) associated whereas exacly %3 are expected.";
  373. for(int j=1; j <= numberOfParametersToProcess; ++j)
  374. {
  375. if (i + j >= arguments.size())
  376. {
  377. this->Internal->ErrorString =
  378. missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess);
  379. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  380. if (ok) { *ok = false; }
  381. return QHash<QString, QVariant>();
  382. }
  383. QString parameter = arguments.at(i + j);
  384. if (this->Internal->Debug)
  385. {
  386. qDebug() << " Processing parameter" << j << ", value:" << parameter;
  387. }
  388. if (this->argumentAdded(parameter))
  389. {
  390. this->Internal->ErrorString =
  391. missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess);
  392. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  393. if (ok) { *ok = false; }
  394. return QHash<QString, QVariant>();
  395. }
  396. if (!currentArgDesc->addParameter(parameter))
  397. {
  398. this->Internal->ErrorString = QString(
  399. "Value(s) associated with argument %1 are incorrect. %2").
  400. arg(argument).arg(currentArgDesc->ExactMatchFailedMessage);
  401. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  402. if (ok) { *ok = false; }
  403. return QHash<QString, QVariant>();
  404. }
  405. }
  406. // Update main loop increment
  407. i = i + numberOfParametersToProcess;
  408. }
  409. else if (numberOfParametersToProcess == -1)
  410. {
  411. if (this->Internal->Debug)
  412. {
  413. qDebug() << " Proccessing StringList ...";
  414. }
  415. int j = 1;
  416. while(j + i < arguments.size())
  417. {
  418. if (this->argumentAdded(arguments.at(j + i)))
  419. {
  420. if (this->Internal->Debug)
  421. {
  422. qDebug() << " No more parameter for" << argument;
  423. }
  424. break;
  425. }
  426. QString parameter = arguments.at(j + i);
  427. if (this->Internal->Debug)
  428. {
  429. qDebug() << " Processing parameter" << j << ", value:" << parameter;
  430. }
  431. if (!currentArgDesc->addParameter(parameter))
  432. {
  433. this->Internal->ErrorString = QString(
  434. "Value(s) associated with argument %1 are incorrect. %2").
  435. arg(argument).arg(currentArgDesc->ExactMatchFailedMessage);
  436. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  437. if (ok) { *ok = false; }
  438. return QHash<QString, QVariant>();
  439. }
  440. j++;
  441. }
  442. // Update main loop increment
  443. i = i + j;
  444. }
  445. }
  446. else
  447. {
  448. if (this->Internal->StrictMode)
  449. {
  450. this->Internal->ErrorString = QString("Unknown argument %1").arg(argument);
  451. error = true;
  452. break;
  453. }
  454. if (this->Internal->Debug)
  455. {
  456. qDebug() << " Skipping: Unknown argument";
  457. }
  458. this->Internal->UnparsedArguments << argument;
  459. }
  460. }
  461. if (ok)
  462. {
  463. *ok = !error;
  464. }
  465. QSettings* settings = 0;
  466. if (this->Internal->UseQSettings && useSettings)
  467. {
  468. if (this->Internal->Settings)
  469. {
  470. settings = this->Internal->Settings;
  471. }
  472. else
  473. {
  474. // Use a default constructed QSettings instance
  475. settings = new QSettings();
  476. }
  477. }
  478. QHash<QString, QVariant> parsedArguments;
  479. QListIterator<CommandLineParserArgumentDescription*> it(this->Internal->ArgumentDescriptionList);
  480. while (it.hasNext())
  481. {
  482. QString key;
  483. CommandLineParserArgumentDescription* desc = it.next();
  484. if (!desc->LongArg.isEmpty())
  485. {
  486. key = desc->LongArg;
  487. }
  488. else
  489. {
  490. key = desc->ShortArg;
  491. }
  492. if (parsedArgDescriptions.contains(desc))
  493. {
  494. // The argument was supplied on the command line, so use the given value
  495. if (this->Internal->MergeSettings && settings)
  496. {
  497. // Merge with QSettings
  498. QVariant settingsVal = settings->value(key);
  499. if (desc->ValueType == QVariant::StringList &&
  500. settingsVal.canConvert(QVariant::StringList))
  501. {
  502. QStringList stringList = desc->Value.toStringList();
  503. stringList.append(settingsVal.toStringList());
  504. parsedArguments.insert(key, stringList);
  505. }
  506. else
  507. {
  508. // do a normal insert
  509. parsedArguments.insert(key, desc->Value);
  510. }
  511. }
  512. else
  513. {
  514. // No merging, just insert all user values
  515. parsedArguments.insert(key, desc->Value);
  516. }
  517. }
  518. else
  519. {
  520. if (settings)
  521. {
  522. // If there is a valid QSettings entry for the argument, use the value
  523. QVariant settingsVal = settings->value(key, desc->Value);
  524. if (!settingsVal.isNull())
  525. {
  526. parsedArguments.insert(key, settingsVal);
  527. }
  528. }
  529. else
  530. {
  531. // Just insert the arguments with valid default values
  532. if (!desc->Value.isNull())
  533. {
  534. parsedArguments.insert(key, desc->Value);
  535. }
  536. }
  537. }
  538. }
  539. // If we created a default QSettings instance, delete it
  540. if (settings && !this->Internal->Settings)
  541. {
  542. delete settings;
  543. }
  544. return parsedArguments;
  545. }
  546. // -------------------------------------------------------------------------
  547. QHash<QString, QVariant> ctkCommandLineParser::parseArguments(int argc, char** argv, bool* ok)
  548. {
  549. QStringList arguments;
  550. // Create a QStringList of arguments
  551. for(int i = 0; i < argc; ++i)
  552. {
  553. arguments << argv[i];
  554. }
  555. return this->parseArguments(arguments, ok);
  556. }
  557. // -------------------------------------------------------------------------
  558. QString ctkCommandLineParser::errorString() const
  559. {
  560. return this->Internal->ErrorString;
  561. }
  562. // -------------------------------------------------------------------------
  563. const QStringList& ctkCommandLineParser::unparsedArguments() const
  564. {
  565. return this->Internal->UnparsedArguments;
  566. }
  567. // --------------------------------------------------------------------------
  568. void ctkCommandLineParser::addArgument(const QString& longarg, const QString& shortarg,
  569. QVariant::Type type, const QString& argHelp,
  570. const QVariant& defaultValue, bool ignoreRest,
  571. bool deprecated)
  572. {
  573. Q_ASSERT_X(!(longarg.isEmpty() && shortarg.isEmpty()), "addArgument",
  574. "both long and short argument names are empty");
  575. if (longarg.isEmpty() && shortarg.isEmpty()) { return; }
  576. Q_ASSERT_X(!defaultValue.isValid() || defaultValue.type() == type, "addArgument",
  577. "defaultValue type does not match");
  578. if (defaultValue.isValid() && defaultValue.type() != type)
  579. throw std::logic_error("The QVariant type of defaultValue does not match the specified type");
  580. /* Make sure it's not already added */
  581. bool added = this->Internal->ArgNameToArgumentDescriptionMap.contains(longarg);
  582. Q_ASSERT_X(!added, "addArgument", "long argument already added");
  583. if (added) { return; }
  584. added = this->Internal->ArgNameToArgumentDescriptionMap.contains(shortarg);
  585. Q_ASSERT_X(!added, "addArgument", "short argument already added");
  586. if (added) { return; }
  587. CommandLineParserArgumentDescription* argDesc =
  588. new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix,
  589. shortarg, this->Internal->ShortPrefix, type,
  590. argHelp, defaultValue, ignoreRest, deprecated);
  591. int argWidth = 0;
  592. if (!longarg.isEmpty())
  593. {
  594. this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc;
  595. argWidth += longarg.length() + this->Internal->LongPrefix.length();
  596. }
  597. if (!shortarg.isEmpty())
  598. {
  599. this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc;
  600. argWidth += shortarg.length() + this->Internal->ShortPrefix.length() + 2;
  601. }
  602. argWidth += 5;
  603. // Set the field width for the arguments
  604. if (argWidth > this->Internal->FieldWidth)
  605. {
  606. this->Internal->FieldWidth = argWidth;
  607. }
  608. this->Internal->ArgumentDescriptionList << argDesc;
  609. this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup] << argDesc;
  610. }
  611. // --------------------------------------------------------------------------
  612. void ctkCommandLineParser::addDeprecatedArgument(
  613. const QString& longarg, const QString& shortarg, const QString& argHelp)
  614. {
  615. addArgument(longarg, shortarg, QVariant::StringList, argHelp, QVariant(), false, true);
  616. }
  617. // --------------------------------------------------------------------------
  618. bool ctkCommandLineParser::setExactMatchRegularExpression(
  619. const QString& argument, const QString& expression, const QString& exactMatchFailedMessage)
  620. {
  621. CommandLineParserArgumentDescription * argDesc =
  622. this->Internal->argumentDescription(argument);
  623. if (!argDesc)
  624. {
  625. return false;
  626. }
  627. if (argDesc->Value.type() == QVariant::Bool)
  628. {
  629. return false;
  630. }
  631. argDesc->RegularExpression = expression;
  632. argDesc->ExactMatchFailedMessage = exactMatchFailedMessage;
  633. return true;
  634. }
  635. // --------------------------------------------------------------------------
  636. int ctkCommandLineParser::fieldWidth() const
  637. {
  638. return this->Internal->FieldWidth;
  639. }
  640. // --------------------------------------------------------------------------
  641. void ctkCommandLineParser::beginGroup(const QString& description)
  642. {
  643. this->Internal->CurrentGroup = description;
  644. }
  645. // --------------------------------------------------------------------------
  646. void ctkCommandLineParser::endGroup()
  647. {
  648. this->Internal->CurrentGroup.clear();
  649. }
  650. // --------------------------------------------------------------------------
  651. void ctkCommandLineParser::enableSettings(const QString& disableLongArg, const QString& disableShortArg)
  652. {
  653. this->Internal->UseQSettings = true;
  654. this->Internal->DisableQSettingsLongArg = disableLongArg;
  655. this->Internal->DisableQSettingsShortArg = disableShortArg;
  656. }
  657. // --------------------------------------------------------------------------
  658. void ctkCommandLineParser::mergeSettings(bool merge)
  659. {
  660. this->Internal->MergeSettings = merge;
  661. }
  662. // --------------------------------------------------------------------------
  663. bool ctkCommandLineParser::settingsEnabled() const
  664. {
  665. return this->Internal->UseQSettings;
  666. }
  667. // --------------------------------------------------------------------------
  668. QString ctkCommandLineParser::helpText(const char charPad) const
  669. {
  670. QString text;
  671. QTextStream stream(&text);
  672. QList<CommandLineParserArgumentDescription*> deprecatedArgs;
  673. // Loop over grouped argument descriptions
  674. QMapIterator<QString, QList<CommandLineParserArgumentDescription*> > it(
  675. this->Internal->GroupToArgumentDescriptionListMap);
  676. while(it.hasNext())
  677. {
  678. it.next();
  679. if (!it.key().isEmpty())
  680. {
  681. stream << "\n" << it.key() << "\n";
  682. }
  683. foreach(CommandLineParserArgumentDescription* argDesc, it.value())
  684. {
  685. if (argDesc->Deprecated)
  686. {
  687. deprecatedArgs << argDesc;
  688. }
  689. else
  690. {
  691. // Extract associated value from settings if any
  692. QString settingsValue;
  693. if (this->Internal->Settings)
  694. {
  695. QString key;
  696. if (!argDesc->LongArg.isEmpty())
  697. {
  698. key = argDesc->LongArg;
  699. }
  700. else
  701. {
  702. key = argDesc->ShortArg;
  703. }
  704. settingsValue = this->Internal->Settings->value(key).toString();
  705. }
  706. stream << argDesc->helpText(this->Internal->FieldWidth, charPad, settingsValue);
  707. }
  708. }
  709. }
  710. if (!deprecatedArgs.empty())
  711. {
  712. stream << "\nDeprecated arguments:\n";
  713. foreach(CommandLineParserArgumentDescription* argDesc, deprecatedArgs)
  714. {
  715. stream << argDesc->helpText(this->Internal->FieldWidth, charPad);
  716. }
  717. }
  718. return text;
  719. }
  720. // --------------------------------------------------------------------------
  721. bool ctkCommandLineParser::argumentAdded(const QString& argument) const
  722. {
  723. return this->Internal->ArgNameToArgumentDescriptionMap.contains(argument);
  724. }
  725. // --------------------------------------------------------------------------
  726. bool ctkCommandLineParser::argumentParsed(const QString& argument) const
  727. {
  728. return this->Internal->ProcessedArguments.contains(argument);
  729. }
  730. // --------------------------------------------------------------------------
  731. void ctkCommandLineParser::setArgumentPrefix(const QString& longPrefix, const QString& shortPrefix)
  732. {
  733. this->Internal->LongPrefix = longPrefix;
  734. this->Internal->ShortPrefix = shortPrefix;
  735. }
  736. // --------------------------------------------------------------------------
  737. void ctkCommandLineParser::setStrictModeEnabled(bool strictMode)
  738. {
  739. this->Internal->StrictMode = strictMode;
  740. }