cmStringCommand.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmStringCommand.h"
  11. #include "cmCryptoHash.h"
  12. #include <cmsys/RegularExpression.hxx>
  13. #include <cmsys/SystemTools.hxx>
  14. #include <stdlib.h> // required for atoi
  15. #include <ctype.h>
  16. #include <time.h>
  17. //----------------------------------------------------------------------------
  18. bool cmStringCommand
  19. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  20. {
  21. if(args.size() < 1)
  22. {
  23. this->SetError("must be called with at least one argument.");
  24. return false;
  25. }
  26. const std::string &subCommand = args[0];
  27. if(subCommand == "REGEX")
  28. {
  29. return this->HandleRegexCommand(args);
  30. }
  31. else if(subCommand == "REPLACE")
  32. {
  33. return this->HandleReplaceCommand(args);
  34. }
  35. else if ( subCommand == "MD5" ||
  36. subCommand == "SHA1" ||
  37. subCommand == "SHA224" ||
  38. subCommand == "SHA256" ||
  39. subCommand == "SHA384" ||
  40. subCommand == "SHA512" )
  41. {
  42. return this->HandleHashCommand(args);
  43. }
  44. else if(subCommand == "TOLOWER")
  45. {
  46. return this->HandleToUpperLowerCommand(args, false);
  47. }
  48. else if(subCommand == "TOUPPER")
  49. {
  50. return this->HandleToUpperLowerCommand(args, true);
  51. }
  52. else if(subCommand == "COMPARE")
  53. {
  54. return this->HandleCompareCommand(args);
  55. }
  56. else if(subCommand == "ASCII")
  57. {
  58. return this->HandleAsciiCommand(args);
  59. }
  60. else if(subCommand == "CONFIGURE")
  61. {
  62. return this->HandleConfigureCommand(args);
  63. }
  64. else if(subCommand == "LENGTH")
  65. {
  66. return this->HandleLengthCommand(args);
  67. }
  68. else if(subCommand == "SUBSTRING")
  69. {
  70. return this->HandleSubstringCommand(args);
  71. }
  72. else if(subCommand == "STRIP")
  73. {
  74. return this->HandleStripCommand(args);
  75. }
  76. else if(subCommand == "RANDOM")
  77. {
  78. return this->HandleRandomCommand(args);
  79. }
  80. else if(subCommand == "FIND")
  81. {
  82. return this->HandleFindCommand(args);
  83. }
  84. std::string e = "does not recognize sub-command "+subCommand;
  85. this->SetError(e.c_str());
  86. return false;
  87. }
  88. //----------------------------------------------------------------------------
  89. bool cmStringCommand::HandleHashCommand(std::vector<std::string> const& args)
  90. {
  91. #if defined(CMAKE_BUILD_WITH_CMAKE)
  92. if(args.size() != 3)
  93. {
  94. cmOStringStream e;
  95. e << args[0] << " requires an output variable and an input string";
  96. this->SetError(e.str().c_str());
  97. return false;
  98. }
  99. cmsys::auto_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
  100. if(hash.get())
  101. {
  102. std::string out = hash->HashString(args[2].c_str());
  103. this->Makefile->AddDefinition(args[1].c_str(), out.c_str());
  104. return true;
  105. }
  106. return false;
  107. #else
  108. cmOStringStream e;
  109. e << args[0] << " not available during bootstrap";
  110. this->SetError(e.str().c_str());
  111. return false;
  112. #endif
  113. }
  114. //----------------------------------------------------------------------------
  115. bool cmStringCommand::HandleToUpperLowerCommand(
  116. std::vector<std::string> const& args, bool toUpper)
  117. {
  118. if ( args.size() < 3 )
  119. {
  120. this->SetError("no output variable specified");
  121. return false;
  122. }
  123. std::string outvar = args[2];
  124. std::string output;
  125. if (toUpper)
  126. {
  127. output = cmSystemTools::UpperCase(args[1]);
  128. }
  129. else
  130. {
  131. output = cmSystemTools::LowerCase(args[1]);
  132. }
  133. // Store the output in the provided variable.
  134. this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
  135. return true;
  136. }
  137. //----------------------------------------------------------------------------
  138. bool cmStringCommand::HandleAsciiCommand(std::vector<std::string> const& args)
  139. {
  140. if ( args.size() < 3 )
  141. {
  142. this->SetError("No output variable specified");
  143. return false;
  144. }
  145. std::string::size_type cc;
  146. std::string outvar = args[args.size()-1];
  147. std::string output = "";
  148. for ( cc = 1; cc < args.size()-1; cc ++ )
  149. {
  150. int ch = atoi(args[cc].c_str());
  151. if ( ch > 0 && ch < 256 )
  152. {
  153. output += static_cast<char>(ch);
  154. }
  155. else
  156. {
  157. std::string error = "Character with code ";
  158. error += args[cc];
  159. error += " does not exist.";
  160. this->SetError(error.c_str());
  161. return false;
  162. }
  163. }
  164. // Store the output in the provided variable.
  165. this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
  166. return true;
  167. }
  168. //----------------------------------------------------------------------------
  169. bool cmStringCommand::HandleConfigureCommand(
  170. std::vector<std::string> const& args)
  171. {
  172. if ( args.size() < 2 )
  173. {
  174. this->SetError("No input string specified.");
  175. return false;
  176. }
  177. else if ( args.size() < 3 )
  178. {
  179. this->SetError("No output variable specified.");
  180. return false;
  181. }
  182. // Parse options.
  183. bool escapeQuotes = false;
  184. bool atOnly = false;
  185. for(unsigned int i = 3; i < args.size(); ++i)
  186. {
  187. if(args[i] == "@ONLY")
  188. {
  189. atOnly = true;
  190. }
  191. else if(args[i] == "ESCAPE_QUOTES")
  192. {
  193. escapeQuotes = true;
  194. }
  195. else
  196. {
  197. cmOStringStream err;
  198. err << "Unrecognized argument \"" << args[i] << "\"";
  199. this->SetError(err.str().c_str());
  200. return false;
  201. }
  202. }
  203. // Configure the string.
  204. std::string output;
  205. this->Makefile->ConfigureString(args[1], output, atOnly, escapeQuotes);
  206. // Store the output in the provided variable.
  207. this->Makefile->AddDefinition(args[2].c_str(), output.c_str());
  208. return true;
  209. }
  210. //----------------------------------------------------------------------------
  211. bool cmStringCommand::HandleRegexCommand(std::vector<std::string> const& args)
  212. {
  213. if(args.size() < 2)
  214. {
  215. this->SetError("sub-command REGEX requires a mode to be specified.");
  216. return false;
  217. }
  218. std::string mode = args[1];
  219. if(mode == "MATCH")
  220. {
  221. if(args.size() < 5)
  222. {
  223. this->SetError("sub-command REGEX, mode MATCH needs "
  224. "at least 5 arguments total to command.");
  225. return false;
  226. }
  227. return this->RegexMatch(args);
  228. }
  229. else if(mode == "MATCHALL")
  230. {
  231. if(args.size() < 5)
  232. {
  233. this->SetError("sub-command REGEX, mode MATCHALL needs "
  234. "at least 5 arguments total to command.");
  235. return false;
  236. }
  237. return this->RegexMatchAll(args);
  238. }
  239. else if(mode == "REPLACE")
  240. {
  241. if(args.size() < 6)
  242. {
  243. this->SetError("sub-command REGEX, mode REPLACE needs "
  244. "at least 6 arguments total to command.");
  245. return false;
  246. }
  247. return this->RegexReplace(args);
  248. }
  249. std::string e = "sub-command REGEX does not recognize mode "+mode;
  250. this->SetError(e.c_str());
  251. return false;
  252. }
  253. //----------------------------------------------------------------------------
  254. bool cmStringCommand::RegexMatch(std::vector<std::string> const& args)
  255. {
  256. //"STRING(REGEX MATCH <regular_expression> <output variable>
  257. // <input> [<input>...])\n";
  258. std::string regex = args[2];
  259. std::string outvar = args[3];
  260. // Concatenate all the last arguments together.
  261. std::string input = args[4];
  262. for(unsigned int i=5; i < args.size(); ++i)
  263. {
  264. input += args[i];
  265. }
  266. this->ClearMatches(this->Makefile);
  267. // Compile the regular expression.
  268. cmsys::RegularExpression re;
  269. if(!re.compile(regex.c_str()))
  270. {
  271. std::string e =
  272. "sub-command REGEX, mode MATCH failed to compile regex \""+regex+"\".";
  273. this->SetError(e.c_str());
  274. return false;
  275. }
  276. // Scan through the input for all matches.
  277. std::string output;
  278. if(re.find(input.c_str()))
  279. {
  280. this->StoreMatches(this->Makefile, re);
  281. std::string::size_type l = re.start();
  282. std::string::size_type r = re.end();
  283. if(r-l == 0)
  284. {
  285. std::string e =
  286. "sub-command REGEX, mode MATCH regex \""+regex+
  287. "\" matched an empty string.";
  288. this->SetError(e.c_str());
  289. return false;
  290. }
  291. output = input.substr(l, r-l);
  292. }
  293. // Store the output in the provided variable.
  294. this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
  295. return true;
  296. }
  297. //----------------------------------------------------------------------------
  298. bool cmStringCommand::RegexMatchAll(std::vector<std::string> const& args)
  299. {
  300. //"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
  301. // [<input>...])\n";
  302. std::string regex = args[2];
  303. std::string outvar = args[3];
  304. // Concatenate all the last arguments together.
  305. std::string input = args[4];
  306. for(unsigned int i=5; i < args.size(); ++i)
  307. {
  308. input += args[i];
  309. }
  310. this->ClearMatches(this->Makefile);
  311. // Compile the regular expression.
  312. cmsys::RegularExpression re;
  313. if(!re.compile(regex.c_str()))
  314. {
  315. std::string e =
  316. "sub-command REGEX, mode MATCHALL failed to compile regex \""+
  317. regex+"\".";
  318. this->SetError(e.c_str());
  319. return false;
  320. }
  321. // Scan through the input for all matches.
  322. std::string output;
  323. const char* p = input.c_str();
  324. while(re.find(p))
  325. {
  326. this->StoreMatches(this->Makefile, re);
  327. std::string::size_type l = re.start();
  328. std::string::size_type r = re.end();
  329. if(r-l == 0)
  330. {
  331. std::string e = "sub-command REGEX, mode MATCHALL regex \""+
  332. regex+"\" matched an empty string.";
  333. this->SetError(e.c_str());
  334. return false;
  335. }
  336. if(output.length() > 0)
  337. {
  338. output += ";";
  339. }
  340. output += std::string(p+l, r-l);
  341. p += r;
  342. }
  343. // Store the output in the provided variable.
  344. this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
  345. return true;
  346. }
  347. //----------------------------------------------------------------------------
  348. bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
  349. {
  350. //"STRING(REGEX REPLACE <regular_expression> <replace_expression>
  351. // <output variable> <input> [<input>...])\n"
  352. std::string regex = args[2];
  353. std::string replace = args[3];
  354. std::string outvar = args[4];
  355. // Pull apart the replace expression to find the escaped [0-9] values.
  356. std::vector<RegexReplacement> replacement;
  357. std::string::size_type l = 0;
  358. while(l < replace.length())
  359. {
  360. std::string::size_type r = replace.find("\\", l);
  361. if(r == std::string::npos)
  362. {
  363. r = replace.length();
  364. replacement.push_back(replace.substr(l, r-l));
  365. }
  366. else
  367. {
  368. if(r-l > 0)
  369. {
  370. replacement.push_back(replace.substr(l, r-l));
  371. }
  372. if(r == (replace.length()-1))
  373. {
  374. this->SetError("sub-command REGEX, mode REPLACE: "
  375. "replace-expression ends in a backslash.");
  376. return false;
  377. }
  378. if((replace[r+1] >= '0') && (replace[r+1] <= '9'))
  379. {
  380. replacement.push_back(replace[r+1]-'0');
  381. }
  382. else if(replace[r+1] == 'n')
  383. {
  384. replacement.push_back("\n");
  385. }
  386. else if(replace[r+1] == '\\')
  387. {
  388. replacement.push_back("\\");
  389. }
  390. else
  391. {
  392. std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
  393. e += replace.substr(r, 2);
  394. e += "\" in replace-expression.";
  395. this->SetError(e.c_str());
  396. return false;
  397. }
  398. r += 2;
  399. }
  400. l = r;
  401. }
  402. // Concatenate all the last arguments together.
  403. std::string input = args[5];
  404. for(unsigned int i=6; i < args.size(); ++i)
  405. {
  406. input += args[i];
  407. }
  408. this->ClearMatches(this->Makefile);
  409. // Compile the regular expression.
  410. cmsys::RegularExpression re;
  411. if(!re.compile(regex.c_str()))
  412. {
  413. std::string e =
  414. "sub-command REGEX, mode REPLACE failed to compile regex \""+
  415. regex+"\".";
  416. this->SetError(e.c_str());
  417. return false;
  418. }
  419. // Scan through the input for all matches.
  420. std::string output;
  421. std::string::size_type base = 0;
  422. while(re.find(input.c_str()+base))
  423. {
  424. this->StoreMatches(this->Makefile, re);
  425. std::string::size_type l2 = re.start();
  426. std::string::size_type r = re.end();
  427. // Concatenate the part of the input that was not matched.
  428. output += input.substr(base, l2);
  429. // Make sure the match had some text.
  430. if(r-l2 == 0)
  431. {
  432. std::string e = "sub-command REGEX, mode REPLACE regex \""+
  433. regex+"\" matched an empty string.";
  434. this->SetError(e.c_str());
  435. return false;
  436. }
  437. // Concatenate the replacement for the match.
  438. for(unsigned int i=0; i < replacement.size(); ++i)
  439. {
  440. if(replacement[i].number < 0)
  441. {
  442. // This is just a plain-text part of the replacement.
  443. output += replacement[i].value;
  444. }
  445. else
  446. {
  447. // Replace with part of the match.
  448. int n = replacement[i].number;
  449. std::string::size_type start = re.start(n);
  450. std::string::size_type end = re.end(n);
  451. std::string::size_type len = input.length()-base;
  452. if((start != std::string::npos) && (end != std::string::npos) &&
  453. (start <= len) && (end <= len))
  454. {
  455. output += input.substr(base+start, end-start);
  456. }
  457. else
  458. {
  459. std::string e =
  460. "sub-command REGEX, mode REPLACE: replace expression \""+
  461. replace+"\" contains an out-of-range escape for regex \""+
  462. regex+"\".";
  463. this->SetError(e.c_str());
  464. return false;
  465. }
  466. }
  467. }
  468. // Move past the match.
  469. base += r;
  470. }
  471. // Concatenate the text after the last match.
  472. output += input.substr(base, input.length()-base);
  473. // Store the output in the provided variable.
  474. this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
  475. return true;
  476. }
  477. //----------------------------------------------------------------------------
  478. void cmStringCommand::ClearMatches(cmMakefile* mf)
  479. {
  480. for (unsigned int i=0; i<10; i++)
  481. {
  482. char name[128];
  483. sprintf(name, "CMAKE_MATCH_%d", i);
  484. mf->AddDefinition(name, "");
  485. mf->MarkVariableAsUsed(name);
  486. }
  487. }
  488. //----------------------------------------------------------------------------
  489. void cmStringCommand::StoreMatches(cmMakefile* mf,cmsys::RegularExpression& re)
  490. {
  491. for (unsigned int i=0; i<10; i++)
  492. {
  493. char name[128];
  494. sprintf(name, "CMAKE_MATCH_%d", i);
  495. mf->AddDefinition(name, re.match(i).c_str());
  496. mf->MarkVariableAsUsed(name);
  497. }
  498. }
  499. //----------------------------------------------------------------------------
  500. bool cmStringCommand::HandleFindCommand(std::vector<std::string> const&
  501. args)
  502. {
  503. // check if all required parameters were passed
  504. if(args.size() < 4 || args.size() > 5)
  505. {
  506. this->SetError("sub-command FIND requires 3 or 4 parameters.");
  507. return false;
  508. }
  509. // check if the reverse flag was set or not
  510. bool reverseMode = false;
  511. if(args.size() == 5 && args[4] == "REVERSE")
  512. {
  513. reverseMode = true;
  514. }
  515. // if we have 5 arguments the last one must be REVERSE
  516. if(args.size() == 5 && args[4] != "REVERSE")
  517. {
  518. this->SetError("sub-command FIND: unknown last parameter");
  519. return false;
  520. }
  521. // local parameter names.
  522. const std::string& sstring = args[1];
  523. const std::string& schar = args[2];
  524. const std::string& outvar = args[3];
  525. // ensure that the user cannot accidentally specify REVERSE as a variable
  526. if(outvar == "REVERSE")
  527. {
  528. this->SetError("sub-command FIND does not allow to select REVERSE as "
  529. "the output variable. "
  530. "Maybe you missed the actual output variable?");
  531. return false;
  532. }
  533. // try to find the character and return its position
  534. size_t pos;
  535. if(!reverseMode)
  536. {
  537. pos = sstring.find(schar);
  538. }
  539. else
  540. {
  541. pos = sstring.rfind(schar);
  542. }
  543. if(std::string::npos != pos)
  544. {
  545. cmOStringStream s;
  546. s << pos;
  547. this->Makefile->AddDefinition(outvar.c_str(), s.str().c_str());
  548. return true;
  549. }
  550. // the character was not found, but this is not really an error
  551. this->Makefile->AddDefinition(outvar.c_str(), "-1");
  552. return true;
  553. }
  554. //----------------------------------------------------------------------------
  555. bool cmStringCommand::HandleCompareCommand(std::vector<std::string> const&
  556. args)
  557. {
  558. if(args.size() < 2)
  559. {
  560. this->SetError("sub-command COMPARE requires a mode to be specified.");
  561. return false;
  562. }
  563. std::string mode = args[1];
  564. if((mode == "EQUAL") || (mode == "NOTEQUAL") ||
  565. (mode == "LESS") || (mode == "GREATER"))
  566. {
  567. if(args.size() < 5)
  568. {
  569. std::string e = "sub-command COMPARE, mode ";
  570. e += mode;
  571. e += " needs at least 5 arguments total to command.";
  572. this->SetError(e.c_str());
  573. return false;
  574. }
  575. const std::string& left = args[2];
  576. const std::string& right = args[3];
  577. const std::string& outvar = args[4];
  578. bool result;
  579. if(mode == "LESS")
  580. {
  581. result = (left < right);
  582. }
  583. else if(mode == "GREATER")
  584. {
  585. result = (left > right);
  586. }
  587. else if(mode == "EQUAL")
  588. {
  589. result = (left == right);
  590. }
  591. else // if(mode == "NOTEQUAL")
  592. {
  593. result = !(left == right);
  594. }
  595. if(result)
  596. {
  597. this->Makefile->AddDefinition(outvar.c_str(), "1");
  598. }
  599. else
  600. {
  601. this->Makefile->AddDefinition(outvar.c_str(), "0");
  602. }
  603. return true;
  604. }
  605. std::string e = "sub-command COMPARE does not recognize mode "+mode;
  606. this->SetError(e.c_str());
  607. return false;
  608. }
  609. //----------------------------------------------------------------------------
  610. bool cmStringCommand::HandleReplaceCommand(std::vector<std::string> const&
  611. args)
  612. {
  613. if(args.size() < 5)
  614. {
  615. this->SetError("sub-command REPLACE requires at least four arguments.");
  616. return false;
  617. }
  618. const std::string& matchExpression = args[1];
  619. const std::string& replaceExpression = args[2];
  620. const std::string& variableName = args[3];
  621. std::string input = args[4];
  622. for(unsigned int i=5; i < args.size(); ++i)
  623. {
  624. input += args[i];
  625. }
  626. cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
  627. replaceExpression.c_str());
  628. this->Makefile->AddDefinition(variableName.c_str(), input.c_str());
  629. return true;
  630. }
  631. //----------------------------------------------------------------------------
  632. bool cmStringCommand::HandleSubstringCommand(std::vector<std::string> const&
  633. args)
  634. {
  635. if(args.size() != 5)
  636. {
  637. this->SetError("sub-command SUBSTRING requires four arguments.");
  638. return false;
  639. }
  640. const std::string& stringValue = args[1];
  641. int begin = atoi(args[2].c_str());
  642. int end = atoi(args[3].c_str());
  643. const std::string& variableName = args[4];
  644. size_t stringLength = stringValue.size();
  645. int intStringLength = static_cast<int>(stringLength);
  646. if ( begin < 0 || begin > intStringLength )
  647. {
  648. cmOStringStream ostr;
  649. ostr << "begin index: " << begin << " is out of range 0 - "
  650. << stringLength;
  651. this->SetError(ostr.str().c_str());
  652. return false;
  653. }
  654. int leftOverLength = intStringLength - begin;
  655. if ( end < -1 || end > leftOverLength )
  656. {
  657. cmOStringStream ostr;
  658. ostr << "end index: " << end << " is out of range -1 - "
  659. << leftOverLength;
  660. this->SetError(ostr.str().c_str());
  661. return false;
  662. }
  663. this->Makefile->AddDefinition(variableName.c_str(),
  664. stringValue.substr(begin, end).c_str());
  665. return true;
  666. }
  667. //----------------------------------------------------------------------------
  668. bool cmStringCommand
  669. ::HandleLengthCommand(std::vector<std::string> const& args)
  670. {
  671. if(args.size() != 3)
  672. {
  673. this->SetError("sub-command LENGTH requires two arguments.");
  674. return false;
  675. }
  676. const std::string& stringValue = args[1];
  677. const std::string& variableName = args[2];
  678. size_t length = stringValue.size();
  679. char buffer[1024];
  680. sprintf(buffer, "%d", static_cast<int>(length));
  681. this->Makefile->AddDefinition(variableName.c_str(), buffer);
  682. return true;
  683. }
  684. //----------------------------------------------------------------------------
  685. bool cmStringCommand::HandleStripCommand(
  686. std::vector<std::string> const& args)
  687. {
  688. if(args.size() != 3)
  689. {
  690. this->SetError("sub-command STRIP requires two arguments.");
  691. return false;
  692. }
  693. const std::string& stringValue = args[1];
  694. const std::string& variableName = args[2];
  695. size_t inStringLength = stringValue.size();
  696. size_t startPos = inStringLength + 1;
  697. size_t endPos = 0;
  698. const char* ptr = stringValue.c_str();
  699. size_t cc;
  700. for ( cc = 0; cc < inStringLength; ++ cc )
  701. {
  702. if ( !isspace(*ptr) )
  703. {
  704. if ( startPos > inStringLength )
  705. {
  706. startPos = cc;
  707. }
  708. endPos = cc;
  709. }
  710. ++ ptr;
  711. }
  712. size_t outLength = 0;
  713. // if the input string didn't contain any non-space characters, return
  714. // an empty string
  715. if (startPos > inStringLength)
  716. {
  717. outLength = 0;
  718. startPos = 0;
  719. }
  720. else
  721. {
  722. outLength=endPos - startPos + 1;
  723. }
  724. this->Makefile->AddDefinition(variableName.c_str(),
  725. stringValue.substr(startPos, outLength).c_str());
  726. return true;
  727. }
  728. //----------------------------------------------------------------------------
  729. bool cmStringCommand
  730. ::HandleRandomCommand(std::vector<std::string> const& args)
  731. {
  732. if(args.size() < 2 || args.size() == 3 || args.size() == 5)
  733. {
  734. this->SetError("sub-command RANDOM requires at least one argument.");
  735. return false;
  736. }
  737. static bool seeded = false;
  738. bool force_seed = false;
  739. unsigned int seed = 0;
  740. int length = 5;
  741. const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
  742. "QWERTYUIOPASDFGHJKLZXCVBNM"
  743. "0123456789";
  744. std::string alphabet;
  745. if ( args.size() > 3 )
  746. {
  747. size_t i = 1;
  748. size_t stopAt = args.size() - 2;
  749. for ( ; i < stopAt; ++i )
  750. {
  751. if ( args[i] == "LENGTH" )
  752. {
  753. ++i;
  754. length = atoi(args[i].c_str());
  755. }
  756. else if ( args[i] == "ALPHABET" )
  757. {
  758. ++i;
  759. alphabet = args[i];
  760. }
  761. else if ( args[i] == "RANDOM_SEED" )
  762. {
  763. ++i;
  764. seed = static_cast<unsigned int>(atoi(args[i].c_str()));
  765. force_seed = true;
  766. }
  767. }
  768. }
  769. if ( !alphabet.size() )
  770. {
  771. alphabet = cmStringCommandDefaultAlphabet;
  772. }
  773. double sizeofAlphabet = static_cast<double>(alphabet.size());
  774. if ( sizeofAlphabet < 1 )
  775. {
  776. this->SetError("sub-command RANDOM invoked with bad alphabet.");
  777. return false;
  778. }
  779. if ( length < 1 )
  780. {
  781. this->SetError("sub-command RANDOM invoked with bad length.");
  782. return false;
  783. }
  784. const std::string& variableName = args[args.size()-1];
  785. std::vector<char> result;
  786. if (!seeded || force_seed)
  787. {
  788. seeded = true;
  789. srand(force_seed? seed : cmSystemTools::RandomSeed());
  790. }
  791. const char* alphaPtr = alphabet.c_str();
  792. int cc;
  793. for ( cc = 0; cc < length; cc ++ )
  794. {
  795. int idx=(int) (sizeofAlphabet* rand()/(RAND_MAX+1.0));
  796. result.push_back(*(alphaPtr + idx));
  797. }
  798. result.push_back(0);
  799. this->Makefile->AddDefinition(variableName.c_str(), &*result.begin());
  800. return true;
  801. }