cmListCommand.cxx 16 KB

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