CommandLineArguments.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. /*=========================================================================
  2. Program: KWSys - Kitware System Library
  3. Module: $RCSfile$
  4. Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
  5. See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even
  7. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  8. PURPOSE. See the above copyright notices for more information.
  9. =========================================================================*/
  10. #include "kwsysPrivate.h"
  11. #include KWSYS_HEADER(CommandLineArguments.hxx)
  12. #include KWSYS_HEADER(Configure.hxx)
  13. #include KWSYS_HEADER(stl/vector)
  14. #include KWSYS_HEADER(stl/map)
  15. #include KWSYS_HEADER(stl/set)
  16. #include KWSYS_HEADER(ios/sstream)
  17. #include KWSYS_HEADER(ios/iostream)
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. namespace KWSYS_NAMESPACE
  21. {
  22. //----------------------------------------------------------------------------
  23. //============================================================================
  24. class CommandLineArgumentsString : public kwsys_stl::string
  25. {
  26. public:
  27. typedef kwsys_stl::string StdString;
  28. CommandLineArgumentsString(): StdString() {}
  29. CommandLineArgumentsString(const value_type* s): StdString(s) {}
  30. CommandLineArgumentsString(const value_type* s, size_type n): StdString(s, n) {}
  31. CommandLineArgumentsString(const StdString& s, size_type pos=0, size_type n=npos):
  32. StdString(s, pos, n) {}
  33. };
  34. class CommandLineArgumentsVectorOfStrings :
  35. public kwsys_stl::vector<CommandLineArgumentsString> {};
  36. class CommandLineArgumentsSetOfStrings :
  37. public kwsys_stl::set<CommandLineArgumentsString> {};
  38. class CommandLineArgumentsMapOfStrucs :
  39. public kwsys_stl::map<CommandLineArgumentsString,
  40. CommandLineArguments::CallbackStructure> {};
  41. class CommandLineArgumentsInternal
  42. {
  43. public:
  44. CommandLineArgumentsInternal()
  45. {
  46. this->UnknownArgumentCallback = 0;
  47. this->ClientData = 0;
  48. this->LastArgument = 0;
  49. }
  50. typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
  51. typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
  52. typedef CommandLineArgumentsString String;
  53. typedef CommandLineArgumentsSetOfStrings SetOfStrings;
  54. VectorOfStrings Argv;
  55. CallbacksMap Callbacks;
  56. CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
  57. void* ClientData;
  58. VectorOfStrings::size_type LastArgument;
  59. };
  60. //============================================================================
  61. //----------------------------------------------------------------------------
  62. //----------------------------------------------------------------------------
  63. CommandLineArguments::CommandLineArguments()
  64. {
  65. this->Internals = new CommandLineArguments::Internal;
  66. this->Help = "";
  67. this->LineLength = 80;
  68. }
  69. //----------------------------------------------------------------------------
  70. CommandLineArguments::~CommandLineArguments()
  71. {
  72. delete this->Internals;
  73. }
  74. //----------------------------------------------------------------------------
  75. void CommandLineArguments::Initialize(int argc, const char* const argv[])
  76. {
  77. int cc;
  78. this->Initialize();
  79. for ( cc = 1; cc < argc; cc ++ )
  80. {
  81. this->ProcessArgument(argv[cc]);
  82. }
  83. }
  84. //----------------------------------------------------------------------------
  85. void CommandLineArguments::Initialize(int argc, char* argv[])
  86. {
  87. int cc;
  88. this->Initialize();
  89. for ( cc = 1; cc < argc; cc ++ )
  90. {
  91. this->ProcessArgument(argv[cc]);
  92. }
  93. }
  94. //----------------------------------------------------------------------------
  95. void CommandLineArguments::Initialize()
  96. {
  97. this->Internals->Argv.clear();
  98. this->Internals->LastArgument = 0;
  99. }
  100. //----------------------------------------------------------------------------
  101. void CommandLineArguments::ProcessArgument(const char* arg)
  102. {
  103. this->Internals->Argv.push_back(arg);
  104. }
  105. //----------------------------------------------------------------------------
  106. int CommandLineArguments::Parse()
  107. {
  108. CommandLineArguments::Internal::VectorOfStrings::size_type cc;
  109. CommandLineArguments::Internal::VectorOfStrings matches;
  110. for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
  111. {
  112. matches.clear();
  113. CommandLineArguments::Internal::String& arg = this->Internals->Argv[cc];
  114. CommandLineArguments::Internal::CallbacksMap::iterator it;
  115. // Does the argument match to any we know about?
  116. for ( it = this->Internals->Callbacks.begin();
  117. it != this->Internals->Callbacks.end();
  118. it ++ )
  119. {
  120. const CommandLineArguments::Internal::String& parg = it->first;
  121. CommandLineArguments::CallbackStructure *cs = &it->second;
  122. if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
  123. cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT)
  124. {
  125. if ( arg == parg )
  126. {
  127. matches.push_back(parg);
  128. }
  129. }
  130. else if ( arg.find( parg ) == 0 )
  131. {
  132. matches.push_back(parg);
  133. }
  134. }
  135. if ( matches.size() > 0 )
  136. {
  137. // Ok, we found one or more arguments that match what user specified.
  138. // Let's find the longest one.
  139. CommandLineArguments::Internal::VectorOfStrings::size_type kk;
  140. CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
  141. CommandLineArguments::Internal::String::size_type maxlen = 0;
  142. for ( kk = 0; kk < matches.size(); kk ++ )
  143. {
  144. if ( matches[kk].size() > maxlen )
  145. {
  146. maxlen = matches[kk].size();
  147. maxidx = kk;
  148. }
  149. }
  150. // So, the longest one is probably the right one. Now see if it has any
  151. // additional value
  152. const char* value = 0;
  153. CommandLineArguments::CallbackStructure *cs
  154. = &this->Internals->Callbacks[matches[maxidx]];
  155. const CommandLineArguments::Internal::String& sarg = matches[maxidx];
  156. if ( cs->ArgumentType == NO_ARGUMENT )
  157. {
  158. // No value
  159. }
  160. else if ( cs->ArgumentType == SPACE_ARGUMENT )
  161. {
  162. if ( cc == this->Internals->Argv.size()-1 )
  163. {
  164. return 0;
  165. }
  166. // Value is the next argument
  167. value = this->Internals->Argv[cc+1].c_str();
  168. cc ++;
  169. }
  170. else if ( cs->ArgumentType == EQUAL_ARGUMENT )
  171. {
  172. if ( arg.size() == sarg.size() || *(arg.c_str() + sarg.size()) != '=' )
  173. {
  174. return 0;
  175. }
  176. // Value is everythng followed the '=' sign
  177. value = arg.c_str() + sarg.size()+1;
  178. }
  179. else if ( cs->ArgumentType == CONCAT_ARGUMENT )
  180. {
  181. // Value is whatever follows the argument
  182. value = arg.c_str() + sarg.size();
  183. }
  184. // Call the callback
  185. if ( cs->Callback )
  186. {
  187. if ( !cs->Callback(sarg.c_str(), value, cs->CallData) )
  188. {
  189. return 0;
  190. }
  191. }
  192. if ( cs->Variable )
  193. {
  194. kwsys_stl::string var = "1";
  195. if ( value )
  196. {
  197. var = value;
  198. }
  199. if ( cs->VariableType == CommandLineArguments::INT_TYPE )
  200. {
  201. int* variable = static_cast<int*>(cs->Variable);
  202. char* res = 0;
  203. *variable = strtol(var.c_str(), &res, 10);
  204. //if ( res && *res )
  205. // {
  206. // Can handle non-int
  207. // }
  208. }
  209. else if ( cs->VariableType == CommandLineArguments::DOUBLE_TYPE )
  210. {
  211. double* variable = static_cast<double*>(cs->Variable);
  212. char* res = 0;
  213. *variable = strtod(var.c_str(), &res);
  214. //if ( res && *res )
  215. // {
  216. // Can handle non-int
  217. // }
  218. }
  219. else if ( cs->VariableType == CommandLineArguments::STRING_TYPE )
  220. {
  221. char** variable = static_cast<char**>(cs->Variable);
  222. if ( *variable )
  223. {
  224. delete [] *variable;
  225. *variable = 0;
  226. }
  227. *variable = new char[ strlen(var.c_str()) + 1 ];
  228. strcpy(*variable, var.c_str());
  229. }
  230. else if ( cs->VariableType == CommandLineArguments::STL_STRING_TYPE )
  231. {
  232. kwsys_stl::string* variable = static_cast<kwsys_stl::string*>(cs->Variable);
  233. *variable = var;
  234. }
  235. else if ( cs->VariableType == CommandLineArguments::BOOL_TYPE )
  236. {
  237. bool* variable = static_cast<bool*>(cs->Variable);
  238. if ( var == "1" || var == "ON" || var == "TRUE" || var == "true" || var == "on" ||
  239. var == "True" || var == "yes" || var == "Yes" || var == "YES" )
  240. {
  241. *variable = true;
  242. }
  243. else
  244. {
  245. *variable = false;
  246. }
  247. }
  248. else
  249. {
  250. kwsys_ios::cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << kwsys_ios::endl;
  251. return 0;
  252. }
  253. }
  254. }
  255. else
  256. {
  257. // Handle unknown arguments
  258. if ( this->Internals->UnknownArgumentCallback )
  259. {
  260. if ( !this->Internals->UnknownArgumentCallback(arg.c_str(),
  261. this->Internals->ClientData) )
  262. {
  263. return 0;
  264. }
  265. return 1;
  266. }
  267. else
  268. {
  269. kwsys_ios::cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << kwsys_ios::endl;
  270. return 0;
  271. }
  272. }
  273. }
  274. // We are done parsing, so remember what was the last argument
  275. this->Internals->LastArgument = cc;
  276. return 1;
  277. }
  278. //----------------------------------------------------------------------------
  279. void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
  280. {
  281. CommandLineArguments::Internal::VectorOfStrings::size_type size
  282. = this->Internals->Argv.size() - this->Internals->LastArgument + 1;
  283. CommandLineArguments::Internal::VectorOfStrings::size_type cc;
  284. char** args = new char*[ size ];
  285. args[0] = new char[ this->Internals->Argv[0].size() + 1 ];
  286. strcpy(args[0], this->Internals->Argv[0].c_str());
  287. int cnt = 1;
  288. for ( cc = this->Internals->LastArgument;
  289. cc < this->Internals->Argv.size(); cc ++ )
  290. {
  291. args[cnt] = new char[ this->Internals->Argv[cc].size() + 1];
  292. strcpy(args[cnt], this->Internals->Argv[cc].c_str());
  293. cnt ++;
  294. }
  295. *argc = cnt;
  296. *argv = args;
  297. }
  298. //----------------------------------------------------------------------------
  299. void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type,
  300. CallbackType callback, void* call_data, const char* help)
  301. {
  302. CommandLineArguments::CallbackStructure s;
  303. s.Argument = argument;
  304. s.ArgumentType = type;
  305. s.Callback = callback;
  306. s.CallData = call_data;
  307. s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
  308. s.Variable = 0;
  309. s.Help = help;
  310. this->Internals->Callbacks[argument] = s;
  311. this->GenerateHelp();
  312. }
  313. //----------------------------------------------------------------------------
  314. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  315. VariableTypeEnum vtype, void* variable, const char* help)
  316. {
  317. CommandLineArguments::CallbackStructure s;
  318. s.Argument = argument;
  319. s.ArgumentType = type;
  320. s.Callback = 0;
  321. s.CallData = 0;
  322. s.VariableType = vtype;
  323. s.Variable = variable;
  324. s.Help = help;
  325. this->Internals->Callbacks[argument] = s;
  326. this->GenerateHelp();
  327. }
  328. //----------------------------------------------------------------------------
  329. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  330. int* variable, const char* help)
  331. {
  332. this->AddArgument(argument, type, CommandLineArguments::INT_TYPE, variable, help);
  333. }
  334. //----------------------------------------------------------------------------
  335. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  336. double* variable, const char* help)
  337. {
  338. this->AddArgument(argument, type, CommandLineArguments::DOUBLE_TYPE, variable, help);
  339. }
  340. //----------------------------------------------------------------------------
  341. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  342. char** variable, const char* help)
  343. {
  344. this->AddArgument(argument, type, CommandLineArguments::STRING_TYPE, variable, help);
  345. }
  346. //----------------------------------------------------------------------------
  347. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  348. kwsys_stl::string* variable, const char* help)
  349. {
  350. this->AddArgument(argument, type, CommandLineArguments::STL_STRING_TYPE, variable, help);
  351. }
  352. //----------------------------------------------------------------------------
  353. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  354. bool* variable, const char* help)
  355. {
  356. this->AddArgument(argument, type, CommandLineArguments::BOOL_TYPE, variable, help);
  357. }
  358. //----------------------------------------------------------------------------
  359. void CommandLineArguments::AddBooleanArgument(const char* argument, bool*
  360. variable, const char* help)
  361. {
  362. this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
  363. CommandLineArguments::BOOL_TYPE, variable, help);
  364. }
  365. //----------------------------------------------------------------------------
  366. void CommandLineArguments::AddBooleanArgument(const char* argument, int*
  367. variable, const char* help)
  368. {
  369. this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
  370. CommandLineArguments::INT_TYPE, variable, help);
  371. }
  372. //----------------------------------------------------------------------------
  373. void CommandLineArguments::SetClientData(void* client_data)
  374. {
  375. this->Internals->ClientData = client_data;
  376. }
  377. //----------------------------------------------------------------------------
  378. void CommandLineArguments::SetUnknownArgumentCallback(
  379. CommandLineArguments::ErrorCallbackType callback)
  380. {
  381. this->Internals->UnknownArgumentCallback = callback;
  382. }
  383. //----------------------------------------------------------------------------
  384. const char* CommandLineArguments::GetHelp(const char* arg)
  385. {
  386. CommandLineArguments::Internal::CallbacksMap::iterator it
  387. = this->Internals->Callbacks.find(arg);
  388. if ( it == this->Internals->Callbacks.end() )
  389. {
  390. return 0;
  391. }
  392. // Since several arguments may point to the same argument, find the one this
  393. // one point to if this one is pointing to another argument.
  394. CommandLineArguments::CallbackStructure *cs = &(it->second);
  395. while ( 1 )
  396. {
  397. CommandLineArguments::Internal::CallbacksMap::iterator hit
  398. = this->Internals->Callbacks.find(cs->Help);
  399. if ( hit == this->Internals->Callbacks.end() )
  400. {
  401. return cs->Help;
  402. }
  403. cs = &(hit->second);
  404. }
  405. // Should never happened
  406. return 0;
  407. }
  408. //----------------------------------------------------------------------------
  409. void CommandLineArguments::GenerateHelp()
  410. {
  411. kwsys_ios::ostringstream str;
  412. // Collapse all arguments into the map of vectors of all arguments that do
  413. // the same thing.
  414. CommandLineArguments::Internal::CallbacksMap::iterator it;
  415. typedef kwsys_stl::map<CommandLineArguments::Internal::String,
  416. CommandLineArguments::Internal::SetOfStrings > MapArgs;
  417. MapArgs mp;
  418. MapArgs::iterator mpit, smpit;
  419. for ( it = this->Internals->Callbacks.begin();
  420. it != this->Internals->Callbacks.end();
  421. it ++ )
  422. {
  423. CommandLineArguments::CallbackStructure *cs = &(it->second);
  424. mpit = mp.find(cs->Help);
  425. if ( mpit != mp.end() )
  426. {
  427. mpit->second.insert(it->first);
  428. mp[it->first].insert(it->first);
  429. }
  430. else
  431. {
  432. mp[it->first].insert(it->first);
  433. }
  434. }
  435. for ( it = this->Internals->Callbacks.begin();
  436. it != this->Internals->Callbacks.end();
  437. it ++ )
  438. {
  439. CommandLineArguments::CallbackStructure *cs = &(it->second);
  440. mpit = mp.find(cs->Help);
  441. if ( mpit != mp.end() )
  442. {
  443. mpit->second.insert(it->first);
  444. smpit = mp.find(it->first);
  445. CommandLineArguments::Internal::SetOfStrings::iterator sit;
  446. for ( sit = smpit->second.begin(); sit != smpit->second.end(); sit++ )
  447. {
  448. mpit->second.insert(*sit);
  449. }
  450. mp.erase(smpit);
  451. }
  452. else
  453. {
  454. mp[it->first].insert(it->first);
  455. }
  456. }
  457. // Find the length of the longest string
  458. CommandLineArguments::Internal::String::size_type maxlen = 0;
  459. for ( mpit = mp.begin();
  460. mpit != mp.end();
  461. mpit ++ )
  462. {
  463. CommandLineArguments::Internal::SetOfStrings::iterator sit;
  464. for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
  465. {
  466. CommandLineArguments::Internal::String::size_type clen = sit->size();
  467. switch ( this->Internals->Callbacks[*sit].ArgumentType )
  468. {
  469. case CommandLineArguments::NO_ARGUMENT: clen += 0; break;
  470. case CommandLineArguments::CONCAT_ARGUMENT: clen += 6; break;
  471. case CommandLineArguments::SPACE_ARGUMENT: clen += 7; break;
  472. case CommandLineArguments::EQUAL_ARGUMENT: clen += 7; break;
  473. }
  474. if ( clen > maxlen )
  475. {
  476. maxlen = clen;
  477. }
  478. }
  479. }
  480. // Create format for that string
  481. char format[80];
  482. sprintf(format, "%%%ds", static_cast<unsigned int>(maxlen));
  483. // Print help for each option
  484. for ( mpit = mp.begin();
  485. mpit != mp.end();
  486. mpit ++ )
  487. {
  488. CommandLineArguments::Internal::SetOfStrings::iterator sit;
  489. for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
  490. {
  491. str << kwsys_ios::endl;
  492. char argument[100];
  493. sprintf(argument, sit->c_str());
  494. switch ( this->Internals->Callbacks[*sit].ArgumentType )
  495. {
  496. case CommandLineArguments::NO_ARGUMENT: break;
  497. case CommandLineArguments::CONCAT_ARGUMENT: strcat(argument, "option"); break;
  498. case CommandLineArguments::SPACE_ARGUMENT: strcat(argument, " option"); break;
  499. case CommandLineArguments::EQUAL_ARGUMENT: strcat(argument, "=option"); break;
  500. }
  501. char buffer[80];
  502. sprintf(buffer, format, argument);
  503. str << buffer;
  504. }
  505. str << "\t";
  506. const char* ptr = this->Internals->Callbacks[mpit->first].Help;
  507. int len = strlen(ptr);
  508. int cnt = 0;
  509. while ( len > 0)
  510. {
  511. // If argument with help is longer than line length, split it on previous
  512. // space (or tab) and continue on the next line
  513. CommandLineArguments::Internal::String::size_type cc;
  514. for ( cc = 0; ptr[cc]; cc ++ )
  515. {
  516. if ( *ptr == ' ' || *ptr == '\t' )
  517. {
  518. ptr ++;
  519. len --;
  520. }
  521. }
  522. if ( cnt > 0 )
  523. {
  524. for ( cc = 0; cc < maxlen; cc ++ )
  525. {
  526. str << " ";
  527. }
  528. str << "\t";
  529. }
  530. CommandLineArguments::Internal::String::size_type skip = len;
  531. if ( skip > this->LineLength - maxlen )
  532. {
  533. skip = this->LineLength - maxlen;
  534. for ( cc = skip-1; cc > 0; cc -- )
  535. {
  536. if ( ptr[cc] == ' ' || ptr[cc] == '\t' )
  537. {
  538. break;
  539. }
  540. }
  541. if ( cc != 0 )
  542. {
  543. skip = cc;
  544. }
  545. }
  546. str.write(ptr, skip);
  547. str << kwsys_ios::endl;
  548. ptr += skip;
  549. len -= skip;
  550. cnt ++;
  551. }
  552. }
  553. this->Help = str.str();
  554. }
  555. } // namespace KWSYS_NAMESPACE