cmListCommand.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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 "cmListCommand.h"
  11. #include <cmsys/RegularExpression.hxx>
  12. #include <cmsys/SystemTools.hxx>
  13. #include <stdlib.h> // required for atoi
  14. #include <ctype.h>
  15. #include <assert.h>
  16. //----------------------------------------------------------------------------
  17. bool cmListCommand
  18. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  19. {
  20. if(args.size() < 2)
  21. {
  22. this->SetError("must be called with at least two arguments.");
  23. return false;
  24. }
  25. const std::string &subCommand = args[0];
  26. if(subCommand == "LENGTH")
  27. {
  28. return this->HandleLengthCommand(args);
  29. }
  30. if(subCommand == "GET")
  31. {
  32. return this->HandleGetCommand(args);
  33. }
  34. if(subCommand == "APPEND")
  35. {
  36. return this->HandleAppendCommand(args);
  37. }
  38. if(subCommand == "FIND")
  39. {
  40. return this->HandleFindCommand(args);
  41. }
  42. if(subCommand == "INSERT")
  43. {
  44. return this->HandleInsertCommand(args);
  45. }
  46. if(subCommand == "REMOVE_AT")
  47. {
  48. return this->HandleRemoveAtCommand(args);
  49. }
  50. if(subCommand == "REMOVE_ITEM")
  51. {
  52. return this->HandleRemoveItemCommand(args);
  53. }
  54. if(subCommand == "REMOVE_DUPLICATES")
  55. {
  56. return this->HandleRemoveDuplicatesCommand(args);
  57. }
  58. if(subCommand == "SORT")
  59. {
  60. return this->HandleSortCommand(args);
  61. }
  62. if(subCommand == "REVERSE")
  63. {
  64. return this->HandleReverseCommand(args);
  65. }
  66. std::string e = "does not recognize sub-command "+subCommand;
  67. this->SetError(e.c_str());
  68. return false;
  69. }
  70. //----------------------------------------------------------------------------
  71. bool cmListCommand::GetListString(std::string& listString,
  72. const std::string& var)
  73. {
  74. // get the old value
  75. const char* cacheValue
  76. = this->Makefile->GetDefinition(var);
  77. if(!cacheValue)
  78. {
  79. return false;
  80. }
  81. listString = cacheValue;
  82. return true;
  83. }
  84. //----------------------------------------------------------------------------
  85. bool cmListCommand::GetList(std::vector<std::string>& list,
  86. const std::string& var)
  87. {
  88. std::string listString;
  89. if ( !this->GetListString(listString, var) )
  90. {
  91. return false;
  92. }
  93. // if the size of the list
  94. if(listString.size() == 0)
  95. {
  96. return true;
  97. }
  98. // expand the variable into a list
  99. cmSystemTools::ExpandListArgument(listString, list, true);
  100. // check the list for empty values
  101. bool hasEmpty = false;
  102. for(std::vector<std::string>::iterator i = list.begin();
  103. i != list.end(); ++i)
  104. {
  105. if(i->size() == 0)
  106. {
  107. hasEmpty = true;
  108. break;
  109. }
  110. }
  111. // if no empty elements then just return
  112. if(!hasEmpty)
  113. {
  114. return true;
  115. }
  116. // if we have empty elements we need to check policy CMP0007
  117. switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0007))
  118. {
  119. case cmPolicies::WARN:
  120. {
  121. // Default is to warn and use old behavior
  122. // OLD behavior is to allow compatibility, so recall
  123. // ExpandListArgument without the true which will remove
  124. // empty values
  125. list.clear();
  126. cmSystemTools::ExpandListArgument(listString, list);
  127. std::string warn = this->Makefile->GetPolicies()->
  128. GetPolicyWarning(cmPolicies::CMP0007);
  129. warn += " List has value = [";
  130. warn += listString;
  131. warn += "].";
  132. this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
  133. warn);
  134. return true;
  135. }
  136. case cmPolicies::OLD:
  137. // OLD behavior is to allow compatibility, so recall
  138. // ExpandListArgument without the true which will remove
  139. // empty values
  140. list.clear();
  141. cmSystemTools::ExpandListArgument(listString, list);
  142. return true;
  143. case cmPolicies::NEW:
  144. return true;
  145. case cmPolicies::REQUIRED_IF_USED:
  146. case cmPolicies::REQUIRED_ALWAYS:
  147. this->Makefile->IssueMessage(
  148. cmake::FATAL_ERROR,
  149. this->Makefile->GetPolicies()
  150. ->GetRequiredPolicyError(cmPolicies::CMP0007)
  151. );
  152. return false;
  153. }
  154. return true;
  155. }
  156. //----------------------------------------------------------------------------
  157. bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args)
  158. {
  159. if(args.size() != 3)
  160. {
  161. this->SetError("sub-command LENGTH requires two arguments.");
  162. return false;
  163. }
  164. const std::string& listName = args[1];
  165. const std::string& variableName = args[args.size() - 1];
  166. std::vector<std::string> varArgsExpanded;
  167. // do not check the return value here
  168. // if the list var is not found varArgsExpanded will have size 0
  169. // and we will return 0
  170. this->GetList(varArgsExpanded, listName.c_str());
  171. size_t length = varArgsExpanded.size();
  172. char buffer[1024];
  173. sprintf(buffer, "%d", static_cast<int>(length));
  174. this->Makefile->AddDefinition(variableName.c_str(), buffer);
  175. return true;
  176. }
  177. //----------------------------------------------------------------------------
  178. bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args)
  179. {
  180. if(args.size() < 4)
  181. {
  182. this->SetError("sub-command GET requires at least three arguments.");
  183. return false;
  184. }
  185. const std::string& listName = args[1];
  186. const std::string& variableName = args[args.size() - 1];
  187. // expand the variable
  188. std::vector<std::string> varArgsExpanded;
  189. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  190. {
  191. this->Makefile->AddDefinition(variableName.c_str(), "NOTFOUND");
  192. return true;
  193. }
  194. // FIXME: Add policy to make non-existing lists an error like empty lists.
  195. if(varArgsExpanded.empty())
  196. {
  197. this->SetError("GET given empty list");
  198. return false;
  199. }
  200. std::string value;
  201. size_t cc;
  202. const char* sep = "";
  203. for ( cc = 2; cc < args.size()-1; cc ++ )
  204. {
  205. int item = atoi(args[cc].c_str());
  206. value += sep;
  207. sep = ";";
  208. size_t nitem = varArgsExpanded.size();
  209. if ( item < 0 )
  210. {
  211. item = (int)nitem + item;
  212. }
  213. if ( item < 0 || nitem <= (size_t)item )
  214. {
  215. cmOStringStream str;
  216. str << "index: " << item << " out of range (-"
  217. << varArgsExpanded.size() << ", "
  218. << varArgsExpanded.size()-1 << ")";
  219. this->SetError(str.str().c_str());
  220. return false;
  221. }
  222. value += varArgsExpanded[item];
  223. }
  224. this->Makefile->AddDefinition(variableName.c_str(), value.c_str());
  225. return true;
  226. }
  227. //----------------------------------------------------------------------------
  228. bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
  229. {
  230. assert(args.size() >= 2);
  231. // Skip if nothing to append.
  232. if(args.size() < 3)
  233. {
  234. return true;
  235. }
  236. const std::string& listName = args[1];
  237. // expand the variable
  238. std::string listString;
  239. this->GetListString(listString, listName.c_str());
  240. size_t cc;
  241. for ( cc = 2; cc < args.size(); ++ cc )
  242. {
  243. if(listString.size())
  244. {
  245. listString += ";";
  246. }
  247. listString += args[cc];
  248. }
  249. this->Makefile->AddDefinition(listName.c_str(), listString.c_str());
  250. return true;
  251. }
  252. //----------------------------------------------------------------------------
  253. bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
  254. {
  255. if(args.size() != 4)
  256. {
  257. this->SetError("sub-command FIND requires three arguments.");
  258. return false;
  259. }
  260. const std::string& listName = args[1];
  261. const std::string& variableName = args[args.size() - 1];
  262. // expand the variable
  263. std::vector<std::string> varArgsExpanded;
  264. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  265. {
  266. this->Makefile->AddDefinition(variableName.c_str(), "-1");
  267. return true;
  268. }
  269. std::vector<std::string>::iterator it;
  270. unsigned int index = 0;
  271. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  272. {
  273. if ( *it == args[2] )
  274. {
  275. char indexString[32];
  276. sprintf(indexString, "%d", index);
  277. this->Makefile->AddDefinition(variableName.c_str(), indexString);
  278. return true;
  279. }
  280. index++;
  281. }
  282. this->Makefile->AddDefinition(variableName.c_str(), "-1");
  283. return true;
  284. }
  285. //----------------------------------------------------------------------------
  286. bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
  287. {
  288. if(args.size() < 4)
  289. {
  290. this->SetError("sub-command INSERT requires at least three arguments.");
  291. return false;
  292. }
  293. const std::string& listName = args[1];
  294. // expand the variable
  295. int item = atoi(args[2].c_str());
  296. std::vector<std::string> varArgsExpanded;
  297. if((!this->GetList(varArgsExpanded, listName.c_str())
  298. || varArgsExpanded.empty()) && item != 0)
  299. {
  300. cmOStringStream str;
  301. str << "index: " << item << " out of range (0, 0)";
  302. this->SetError(str.str().c_str());
  303. return false;
  304. }
  305. if ( varArgsExpanded.size() != 0 )
  306. {
  307. size_t nitem = varArgsExpanded.size();
  308. if ( item < 0 )
  309. {
  310. item = (int)nitem + item;
  311. }
  312. if ( item < 0 || nitem <= (size_t)item )
  313. {
  314. cmOStringStream str;
  315. str << "index: " << item << " out of range (-"
  316. << varArgsExpanded.size() << ", "
  317. << (varArgsExpanded.size() == 0?0:(varArgsExpanded.size()-1)) << ")";
  318. this->SetError(str.str().c_str());
  319. return false;
  320. }
  321. }
  322. size_t cc;
  323. size_t cnt = 0;
  324. for ( cc = 3; cc < args.size(); ++ cc )
  325. {
  326. varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]);
  327. cnt ++;
  328. }
  329. std::string value;
  330. const char* sep = "";
  331. for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
  332. {
  333. value += sep;
  334. value += varArgsExpanded[cc];
  335. sep = ";";
  336. }
  337. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  338. return true;
  339. }
  340. //----------------------------------------------------------------------------
  341. bool cmListCommand
  342. ::HandleRemoveItemCommand(std::vector<std::string> const& args)
  343. {
  344. if(args.size() < 3)
  345. {
  346. this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
  347. return false;
  348. }
  349. const std::string& listName = args[1];
  350. // expand the variable
  351. std::vector<std::string> varArgsExpanded;
  352. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  353. {
  354. this->SetError("sub-command REMOVE_ITEM requires list to be present.");
  355. return false;
  356. }
  357. size_t cc;
  358. for ( cc = 2; cc < args.size(); ++ cc )
  359. {
  360. size_t kk = 0;
  361. while ( kk < varArgsExpanded.size() )
  362. {
  363. if ( varArgsExpanded[kk] == args[cc] )
  364. {
  365. varArgsExpanded.erase(varArgsExpanded.begin()+kk);
  366. }
  367. else
  368. {
  369. kk ++;
  370. }
  371. }
  372. }
  373. std::string value;
  374. const char* sep = "";
  375. for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
  376. {
  377. value += sep;
  378. value += varArgsExpanded[cc];
  379. sep = ";";
  380. }
  381. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  382. return true;
  383. }
  384. //----------------------------------------------------------------------------
  385. bool cmListCommand
  386. ::HandleReverseCommand(std::vector<std::string> const& args)
  387. {
  388. assert(args.size() >= 2);
  389. if(args.size() > 2)
  390. {
  391. this->SetError(
  392. "sub-command REVERSE only takes one argument.");
  393. return false;
  394. }
  395. const std::string& listName = args[1];
  396. // expand the variable
  397. std::vector<std::string> varArgsExpanded;
  398. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  399. {
  400. this->SetError("sub-command REVERSE requires list to be present.");
  401. return false;
  402. }
  403. std::string value;
  404. std::vector<std::string>::reverse_iterator it;
  405. const char* sep = "";
  406. for ( it = varArgsExpanded.rbegin(); it != varArgsExpanded.rend(); ++ it )
  407. {
  408. value += sep;
  409. value += it->c_str();
  410. sep = ";";
  411. }
  412. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  413. return true;
  414. }
  415. //----------------------------------------------------------------------------
  416. bool cmListCommand
  417. ::HandleRemoveDuplicatesCommand(std::vector<std::string> const& args)
  418. {
  419. assert(args.size() >= 2);
  420. if(args.size() > 2)
  421. {
  422. this->SetError(
  423. "sub-command REMOVE_DUPLICATES only takes one argument.");
  424. return false;
  425. }
  426. const std::string& listName = args[1];
  427. // expand the variable
  428. std::vector<std::string> varArgsExpanded;
  429. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  430. {
  431. this->SetError(
  432. "sub-command REMOVE_DUPLICATES requires list to be present.");
  433. return false;
  434. }
  435. std::string value;
  436. std::set<std::string> unique;
  437. std::vector<std::string>::iterator it;
  438. const char* sep = "";
  439. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  440. {
  441. if (unique.find(*it) != unique.end())
  442. {
  443. continue;
  444. }
  445. unique.insert(*it);
  446. value += sep;
  447. value += it->c_str();
  448. sep = ";";
  449. }
  450. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  451. return true;
  452. }
  453. //----------------------------------------------------------------------------
  454. bool cmListCommand
  455. ::HandleSortCommand(std::vector<std::string> const& args)
  456. {
  457. assert(args.size() >= 2);
  458. if(args.size() > 2)
  459. {
  460. this->SetError(
  461. "sub-command SORT only takes one argument.");
  462. return false;
  463. }
  464. const std::string& listName = args[1];
  465. // expand the variable
  466. std::vector<std::string> varArgsExpanded;
  467. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  468. {
  469. this->SetError("sub-command SORT requires list to be present.");
  470. return false;
  471. }
  472. std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
  473. std::string value;
  474. std::vector<std::string>::iterator it;
  475. const char* sep = "";
  476. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  477. {
  478. value += sep;
  479. value += it->c_str();
  480. sep = ";";
  481. }
  482. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  483. return true;
  484. }
  485. //----------------------------------------------------------------------------
  486. bool cmListCommand::HandleRemoveAtCommand(
  487. std::vector<std::string> const& args)
  488. {
  489. if(args.size() < 3)
  490. {
  491. this->SetError("sub-command REMOVE_AT requires at least "
  492. "two arguments.");
  493. return false;
  494. }
  495. const std::string& listName = args[1];
  496. // expand the variable
  497. std::vector<std::string> varArgsExpanded;
  498. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  499. {
  500. this->SetError("sub-command REMOVE_AT requires list to be present.");
  501. return false;
  502. }
  503. // FIXME: Add policy to make non-existing lists an error like empty lists.
  504. if(varArgsExpanded.empty())
  505. {
  506. this->SetError("REMOVE_AT given empty list");
  507. return false;
  508. }
  509. size_t cc;
  510. std::vector<size_t> removed;
  511. for ( cc = 2; cc < args.size(); ++ cc )
  512. {
  513. int item = atoi(args[cc].c_str());
  514. size_t nitem = varArgsExpanded.size();
  515. if ( item < 0 )
  516. {
  517. item = (int)nitem + item;
  518. }
  519. if ( item < 0 || nitem <= (size_t)item )
  520. {
  521. cmOStringStream str;
  522. str << "index: " << item << " out of range (-"
  523. << varArgsExpanded.size() << ", "
  524. << varArgsExpanded.size()-1 << ")";
  525. this->SetError(str.str().c_str());
  526. return false;
  527. }
  528. removed.push_back(static_cast<size_t>(item));
  529. }
  530. std::string value;
  531. const char* sep = "";
  532. for ( cc = 0; cc < varArgsExpanded.size(); ++ cc )
  533. {
  534. size_t kk;
  535. bool found = false;
  536. for ( kk = 0; kk < removed.size(); ++ kk )
  537. {
  538. if ( cc == removed[kk] )
  539. {
  540. found = true;
  541. }
  542. }
  543. if ( !found )
  544. {
  545. value += sep;
  546. value += varArgsExpanded[cc];
  547. sep = ";";
  548. }
  549. }
  550. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  551. return true;
  552. }